Aptheos's picture
Live base-vs-tuned app
e8b22d2 verified
Raw History Blame Contribute Delete
2.05 kB
"""Deterministic test doubles for browser-control environments."""
from __future__ import annotations
from dataclasses import dataclass, field
from browser_control.environment import BrowserObservation, BrowserStep
@dataclass(slots=True)
class FakeClickTestEnvironment:
"""A one-button task with explicit lifecycle and reward semantics."""
button_id: str = "13"
actions: list[str] = field(default_factory=list, init=False)
_active: bool = field(default=False, init=False, repr=False)
_done: bool = field(default=False, init=False, repr=False)
@property
def expected_action(self) -> str:
return f"click('{self.button_id}')"
def reset(self, *, seed: int | None = None) -> BrowserStep:
del seed
self.actions.clear()
self._active = True
self._done = False
return BrowserStep(
observation=self._observation(),
reward=0.0,
terminated=False,
info={"task": "click-test", "backend": "fake"},
)
def step(self, action: str) -> BrowserStep:
if not self._active:
raise RuntimeError("reset() must be called before step()")
if self._done:
raise RuntimeError("step() cannot be called after the episode is done")
self.actions.append(action)
succeeded = action == self.expected_action
self._done = True
error = None if succeeded else f"invalid action: {action}"
return BrowserStep(
observation=self._observation(error=error),
reward=1.0 if succeeded else 0.0,
terminated=True,
info={"task": "click-test", "success": succeeded, "backend": "fake"},
)
def close(self) -> None:
self._active = False
def _observation(self, *, error: str | None = None) -> BrowserObservation:
return BrowserObservation(
goal="Click the button.",
accessibility_tree=f"[{self.button_id}] button 'Click Me!'",
last_action_error=error,
)