diff --git a/skillopt/types.py b/skillopt/types.py index 9c23edb4..674a0a67 100644 --- a/skillopt/types.py +++ b/skillopt/types.py @@ -11,12 +11,12 @@ """ from __future__ import annotations -from dataclasses import dataclass, field, fields as dc_fields +from dataclasses import dataclass, field +from dataclasses import fields as dc_fields from typing import Any, Literal -from skillopt.evaluation.gate import GateAction, GateResult # noqa: F401 from skillopt.datasets.base import BatchSpec # noqa: F401 - +from skillopt.evaluation.gate import GateAction, GateResult # noqa: F401 # ── Atomic types ───────────────────────────────────────────────────────── @@ -109,7 +109,7 @@ class RolloutResult: """ id: str - hard: int + hard: float soft: float n_turns: int = 0 fail_reason: str = "" @@ -142,7 +142,7 @@ def from_dict(cls, d: dict) -> RolloutResult: extras = {k: v for k, v in d.items() if k not in known} return cls( id=str(d.get("id", "")), - hard=int(d.get("hard", 0)), + hard=float(d.get("hard", 0)), soft=float(d.get("soft", 0.0)), n_turns=int(d.get("n_turns", 0)), fail_reason=str(d.get("fail_reason", "")), diff --git a/tests/test_types.py b/tests/test_types.py index f39c8f62..b31d9e4d 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -3,8 +3,7 @@ import pytest -from skillopt.types import Edit, Patch - +from skillopt.types import Edit, Patch, RolloutResult # ── Edit ──────────────────────────────────────────────────────────────────── @@ -247,3 +246,17 @@ def test_nested_edit_from_dict_handles_dicts(self) -> None: assert isinstance(p.edits[0], Edit) assert p.edits[0].op == "append" assert p.edits[0].content == "hello" + + +# ── RolloutResult ──────────────────────────────────────────────────────────── + + +class TestRolloutResultRoundTrip: + """RolloutResult.to_dict() / RolloutResult.from_dict() round-trip.""" + + def test_preserves_fractional_hard_score(self) -> None: + """Hard can be a continuous reward and must not be truncated.""" + result = RolloutResult.from_dict({"id": "episode-1", "hard": 0.75, "soft": 0.5}) + + assert result.hard == pytest.approx(0.75) + assert result.to_dict()["hard"] == pytest.approx(0.75)