code-debug-env / models.py
VeerCodex's picture
Initial commit - Code Debug Environment
8272e36
Raw
History Blame Contribute Delete
3.6 kB
import random
from pydantic import BaseModel
from typing import Optional
class Action(BaseModel):
fixed_code: str
class Observation(BaseModel):
buggy_code: str
task_description: str
task_id: int
attempts: int
class Reward(BaseModel):
score: float
message: str
TASKS = [
{
"id": 1,
"difficulty": "easy",
"description": "Fix the function so it correctly returns the sum of two numbers.",
"buggy_code": "def add(a, b):\n return a - b",
"expected_output": "7",
"test_input": "add(3, 4)",
},
{
"id": 2,
"difficulty": "medium",
"description": "Fix the function so it correctly returns the largest number in a list.",
"buggy_code": "def find_max(lst):\n max_val = lst[0]\n for num in lst:\n if num < max_val:\n max_val = num\n return max_val",
"expected_output": "9",
"test_input": "find_max([3, 9, 1, 7])",
},
{
"id": 3,
"difficulty": "hard",
"description": "Fix the recursive function so it correctly returns the nth Fibonacci number.",
"buggy_code": "def fib(n):\n if n == 0:\n return 0\n if n == 1:\n return 1\n return fib(n-1) + fib(n-3)",
"expected_output": "8",
"test_input": "fib(6)",
},
]
class CodeDebugEnv:
def __init__(self):
self.current_task = None
self.attempts = 0
self.done = False
def reset(self, task_id: Optional[int] = None) -> Observation:
if task_id is not None:
self.current_task = next((t for t in TASKS if t["id"] == task_id), TASKS[0])
else:
self.current_task = random.choice(TASKS)
self.attempts = 0
self.done = False
return Observation(
buggy_code=self.current_task["buggy_code"],
task_description=self.current_task["description"],
task_id=self.current_task["id"],
attempts=self.attempts,
)
def step(self, action: Action):
if self.done:
return self.state(), Reward(score=0.0, message="Episode already done. Call reset()."), True, {}
self.attempts += 1
score = 0.0
message = ""
try:
local_ns = {}
exec(action.fixed_code, local_ns)
result = str(eval(self.current_task["test_input"], local_ns))
expected = self.current_task["expected_output"]
if result == expected:
if self.attempts == 1:
score = 1.0
message = "Perfect! Fixed in 1 attempt."
elif self.attempts == 2:
score = 0.7
message = "Correct! Fixed in 2 attempts."
else:
score = 0.4
message = "Correct but took too many attempts."
self.done = True
else:
score = 0.1
message = f"Wrong output. Got {result}, expected {expected}."
except Exception as e:
score = 0.0
message = f"Code error: {str(e)}"
return self.state(), Reward(score=score, message=message), self.done, {}
def state(self) -> Observation:
return Observation(
buggy_code=self.current_task["buggy_code"] if self.current_task else "",
task_description=self.current_task["description"] if self.current_task else "",
task_id=self.current_task["id"] if self.current_task else 0,
attempts=self.attempts,
)