solidityguard-openenv / environment.py
tanaymitra98
Initial commit: MetaXScalar project
b214779
Raw
History Blame Contribute Delete
3.21 kB
from __future__ import annotations
import json
import os
from dataclasses import dataclass
from typing import Any, Dict, List, Optional
from graders import grade_action
@dataclass
class EnvironmentState:
task_id: str
step_count: int
max_steps: int
score_so_far: float
done: bool
class SolidityGuardEnv:
def __init__(self, data_path: str = "data/manifest.json") -> None:
self.data_path = data_path
self._load_manifest()
self._index = 0
self._current_sample: Optional[Dict[str, Any]] = None
self._state: Optional[EnvironmentState] = None
def _load_manifest(self) -> None:
if not os.path.exists(self.data_path):
raise FileNotFoundError(f"Manifest not found: {self.data_path}")
with open(self.data_path, "r", encoding="utf-8") as handle:
self._manifest = json.load(handle)
if not isinstance(self._manifest, list) or not self._manifest:
raise ValueError("Manifest must be a non-empty list")
def reset(self, task_id: Optional[str] = None) -> Dict[str, Any]:
if task_id:
candidates = [item for item in self._manifest if item["task_id"] == task_id]
else:
candidates = self._manifest
if not candidates:
raise ValueError("No samples available for the requested task")
self._current_sample = candidates[self._index % len(candidates)]
self._index += 1
source_path = self._current_sample["source_path"]
with open(source_path, "r", encoding="utf-8") as handle:
source_code = handle.read()
observation = {
"source_code": source_code,
"metadata": self._current_sample.get("metadata", {}),
"task_id": self._current_sample["task_id"],
}
self._state = EnvironmentState(
task_id=self._current_sample["task_id"],
step_count=0,
max_steps=1,
score_so_far=0.0,
done=False,
)
return observation
def step(self, action: List[Dict[str, Any]]) -> Dict[str, Any]:
if self._current_sample is None or self._state is None:
raise RuntimeError("Call reset() before step().")
if self._state.done:
return {
"reward": self._state.score_so_far,
"done": True,
"details": {"message": "Episode already completed"},
}
expected = self._current_sample.get("labels", [])
reward, details = grade_action(action, expected)
self._state.step_count += 1
self._state.score_so_far = reward
self._state.done = True
return {
"reward": reward,
"done": True,
"details": details,
}
def state(self) -> Dict[str, Any]:
if self._state is None:
raise RuntimeError("Call reset() before state().")
return {
"task_id": self._state.task_id,
"step_count": self._state.step_count,
"max_steps": self._state.max_steps,
"score_so_far": self._state.score_so_far,
"done": self._state.done,
}