Config-debug / server /graders /grader_api.py
affu143
one more time
13c6248
Raw
History Blame Contribute Delete
4.48 kB
"""
grader_api.py - Class-based graders for OpenEnv validator.
The validator imports these classes from openenv.yaml, instantiates them,
and calls .grade(env, *args, **kwargs) -> float.
How it works:
- The validator passes the Environment object as `env`
- We extract the CURRENT observation's broken_config from the env
- We run our real grading logic on it — same logic used during step()
- The score reflects how good the current config actually is
- Scores are clamped to strict (0.01, 0.90) range
"""
from server.graders.json_grader import grade_task1 as _grade_json
from server.graders.yaml_grader import grade_task2 as _grade_yaml
from server.graders.dockerfile_grader import grade_task3 as _grade_dockerfile
from server.graders.compose_grader import grade_task4 as _grade_compose
from server.graders.k8s_grader import grade_task5 as _grade_k8s
from server.graders.github_actions_grader import grade_task6 as _grade_github_actions
from server.graders.nginx_grader import grade_task7 as _grade_nginx
def _run_grader(grader_fn, task_id, env, *args, **kwargs) -> float:
"""Run the actual grading logic on the environment's current config.
Extracts the config to grade from the environment state.
This is REAL grading — not hardcoded values.
"""
try:
config = None
# 1. If env is a string, grade it directly
if isinstance(env, str):
config = env
# 2. If env is the Environment object, get the current observation's config
elif env is not None:
# Try to get the current broken_config from observation
if hasattr(env, '_build_observation'):
obs = env._build_observation()
config = getattr(obs, 'broken_config', None)
# Or from state
if not config and hasattr(env, 'current_broken_config'):
config = env.current_broken_config
# 3. If still no config, get the broken_config for this task (initial state)
if not config:
from server.tasks.task_registry import get_task, TASK_REGISTRY
if task_id in TASK_REGISTRY:
task = get_task(task_id)
config = task.broken_config # Grade the BROKEN config (should get low score)
# 4. Last resort
if not config:
config = "{}"
# Run the actual grader logic
result = grader_fn(config)
if isinstance(result, (tuple, list)):
score = float(result[0])
else:
score = float(result)
# Clamp to strict (0, 1) — never 0.0 or 1.0
return max(0.01, min(0.90, score))
except Exception as e:
print(f"[GRADER] Error grading {task_id}: {e}")
return 0.50
class Task1Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_json, "task1_json", env, *args, **kwargs)
class Task2Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_yaml, "task2_yaml", env, *args, **kwargs)
class Task3Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_dockerfile, "task3_dockerfile", env, *args, **kwargs)
class Task4Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_compose, "task4_compose", env, *args, **kwargs)
class Task5Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_k8s, "task5_k8s", env, *args, **kwargs)
class Task6Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_github_actions, "task6_github_actions", env, *args, **kwargs)
class Task7Grader:
def grade(self, env=None, *args, **kwargs) -> float:
return _run_grader(_grade_nginx, "task7_nginx", env, *args, **kwargs)
# Function aliases so app.py /grader endpoint and task_registry still work
grade_task1 = Task1Grader().grade
grade_task2 = Task2Grader().grade
grade_task3 = Task3Grader().grade
grade_task4 = Task4Grader().grade
grade_task5 = Task5Grader().grade
grade_task6 = Task6Grader().grade
grade_task7 = Task7Grader().grade
grade_task1_json = grade_task1
grade_task2_yaml = grade_task2
grade_task3_dockerfile = grade_task3
grade_task4_compose = grade_task4
grade_task5_k8s = grade_task5
grade_task6_github_actions = grade_task6
grade_task7_nginx = grade_task7