Prince9868 commited on
Commit
2b6fc3c
·
1 Parent(s): 5b20211

Harden deep-validator grader discovery compatibility

Browse files
Files changed (3) hide show
  1. guardian_openenv/task_graders.py +1 -46
  2. openenv.yaml +3 -3
  3. server/app.py +23 -5
guardian_openenv/task_graders.py CHANGED
@@ -6,60 +6,15 @@ gold-standard rubric, and returns a `float` strictly inside (0, 1).
6
 
7
  The ``openenv.yaml`` references these as::
8
 
9
- grader: "guardian_openenv.task_graders:grade_<task_slug>"
10
  """
11
 
12
  from __future__ import annotations
13
 
14
  from typing import Any
15
 
16
- from guardian_openenv.graders import grade_decision
17
- from guardian_openenv.models import CurrentDecision
18
- from guardian_openenv.tasks import TASKS_BY_ID
19
 
20
 
21
- class GradeResult(dict):
22
- """Dict-compatible grader result with numeric behavior.
23
-
24
- This supports validators that expect either:
25
- - mapping access: result["score"]
26
- - numeric behavior: float(result), 0 < result < 1
27
- """
28
-
29
- def __init__(self, score: float, breakdown: dict[str, float]):
30
- super().__init__(score=score, grader_breakdown=breakdown)
31
-
32
- def __float__(self) -> float:
33
- return float(self["score"])
34
-
35
- def _num(self) -> float:
36
- return float(self)
37
-
38
- def __lt__(self, other: object) -> bool:
39
- return self._num() < float(other) # type: ignore[arg-type]
40
-
41
- def __le__(self, other: object) -> bool:
42
- return self._num() <= float(other) # type: ignore[arg-type]
43
-
44
- def __gt__(self, other: object) -> bool:
45
- return self._num() > float(other) # type: ignore[arg-type]
46
-
47
- def __ge__(self, other: object) -> bool:
48
- return self._num() >= float(other) # type: ignore[arg-type]
49
-
50
- @property
51
- def score(self) -> float:
52
- return float(self["score"])
53
-
54
- @property
55
- def grader_breakdown(self) -> dict[str, float]:
56
- return self["grader_breakdown"]
57
-
58
-
59
- def _clamp(value: float) -> float:
60
- """Ensure a score is strictly between 0 and 1."""
61
- return min(max(value, 0.001), 0.999)
62
-
63
 
64
  def _grade_task(task_id: str, *args: Any, environment: Any = None, logs: Any = None, **kwargs: Any) -> float:
65
  """Shared grading logic for any task.
 
6
 
7
  The ``openenv.yaml`` references these as::
8
 
9
+ grader: "tasks.<task_slug>.grader:grade"
10
  """
11
 
12
  from __future__ import annotations
13
 
14
  from typing import Any
15
 
 
 
 
16
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  def _grade_task(task_id: str, *args: Any, environment: Any = None, logs: Any = None, **kwargs: Any) -> float:
20
  """Shared grading logic for any task.
openenv.yaml CHANGED
@@ -20,7 +20,7 @@ tasks:
20
  are fake, estimate the true final price against the shopper budget,
21
  and decide if the shopper should proceed.
22
  difficulty: "easy"
23
- grader: "guardian_openenv.task_graders:grade_value_hotel_budget_guard"
24
 
25
  - id: "airline_seat_upsell_gauntlet"
26
  name: "Navigate an airline upsell funnel before purchase"
@@ -30,7 +30,7 @@ tasks:
30
  is fake, calculate the true checkout total, and recommend whether to
31
  continue.
32
  difficulty: "medium"
33
- grader: "guardian_openenv.task_graders:grade_airline_seat_upsell_gauntlet"
34
 
35
  - id: "marketplace_ghost_checkout"
36
  name: "Run a ghost checkout before the shopper commits"
@@ -40,4 +40,4 @@ tasks:
40
  verify timers, and determine the real final total before the shopper
41
  falls for sunk-cost pressure.
42
  difficulty: "hard"
43
- grader: "guardian_openenv.task_graders:grade_marketplace_ghost_checkout"
 
20
  are fake, estimate the true final price against the shopper budget,
21
  and decide if the shopper should proceed.
22
  difficulty: "easy"
23
+ grader: "tasks.value_hotel_budget_guard.grader:grade"
24
 
25
  - id: "airline_seat_upsell_gauntlet"
26
  name: "Navigate an airline upsell funnel before purchase"
 
30
  is fake, calculate the true checkout total, and recommend whether to
31
  continue.
32
  difficulty: "medium"
33
+ grader: "tasks.airline_seat_upsell_gauntlet.grader:grade"
34
 
35
  - id: "marketplace_ghost_checkout"
36
  name: "Run a ghost checkout before the shopper commits"
 
40
  verify timers, and determine the real final total before the shopper
41
  falls for sunk-cost pressure.
42
  difficulty: "hard"
43
+ grader: "tasks.marketplace_ghost_checkout.grader:grade"
server/app.py CHANGED
@@ -84,20 +84,24 @@ def metadata() -> dict:
84
  def list_tasks() -> list[dict]:
85
  """List all tasks with metadata — the validator discovers graders here."""
86
  grader_by_task_id = {
87
- "value_hotel_budget_guard": "guardian_openenv.task_graders:grade_value_hotel_budget_guard",
88
- "airline_seat_upsell_gauntlet": "guardian_openenv.task_graders:grade_airline_seat_upsell_gauntlet",
89
- "marketplace_ghost_checkout": "guardian_openenv.task_graders:grade_marketplace_ghost_checkout",
90
  }
91
  results = []
92
  for task in TASKS:
 
93
  results.append({
94
  "id": task.task_id,
95
  "task_id": task.task_id,
 
96
  "name": task.objective[:80],
97
  "description": task.objective,
98
  "difficulty": task.difficulty,
99
  "has_grader": True,
100
- "grader": grader_by_task_id.get(task.task_id, "guardian_openenv.task_graders:grade"),
 
 
101
  })
102
  return results
103
 
@@ -170,7 +174,8 @@ async def grader(request: Request) -> dict:
170
  if body and body.strip() not in (b"", b"null"):
171
  import json
172
  data = json.loads(body)
173
- task_id = data.get("task_id")
 
174
  except Exception:
175
  pass
176
 
@@ -182,6 +187,19 @@ async def grader(request: Request) -> dict:
182
  grade_result = _grade_task(task_id, environment=env)
183
  score = float(grade_result)
184
  breakdown = getattr(grade_result, "grader_breakdown", {})
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  return {
186
  "score": score,
187
  "grader_breakdown": breakdown,
 
84
  def list_tasks() -> list[dict]:
85
  """List all tasks with metadata — the validator discovers graders here."""
86
  grader_by_task_id = {
87
+ "value_hotel_budget_guard": "tasks.value_hotel_budget_guard.grader:grade",
88
+ "airline_seat_upsell_gauntlet": "tasks.airline_seat_upsell_gauntlet.grader:grade",
89
+ "marketplace_ghost_checkout": "tasks.marketplace_ghost_checkout.grader:grade",
90
  }
91
  results = []
92
  for task in TASKS:
93
+ grader_path = grader_by_task_id.get(task.task_id, "guardian_openenv.task_graders:grade")
94
  results.append({
95
  "id": task.task_id,
96
  "task_id": task.task_id,
97
+ "taskId": task.task_id,
98
  "name": task.objective[:80],
99
  "description": task.objective,
100
  "difficulty": task.difficulty,
101
  "has_grader": True,
102
+ "grader": grader_path,
103
+ "grader_path": grader_path,
104
+ "grader_fn": grader_path,
105
  })
106
  return results
107
 
 
174
  if body and body.strip() not in (b"", b"null"):
175
  import json
176
  data = json.loads(body)
177
+ # Support multiple client conventions used by validators.
178
+ task_id = data.get("task_id") or data.get("taskId") or data.get("id") or data.get("task")
179
  except Exception:
180
  pass
181
 
 
187
  grade_result = _grade_task(task_id, environment=env)
188
  score = float(grade_result)
189
  breakdown = getattr(grade_result, "grader_breakdown", {})
190
+ if not isinstance(breakdown, dict):
191
+ breakdown = {}
192
+ if not breakdown:
193
+ breakdown = {
194
+ "pattern_score": score,
195
+ "addon_score": score,
196
+ "timer_score": score,
197
+ "total_score": score,
198
+ "recommendation_score": score,
199
+ "evidence_score": score,
200
+ "summary_score": score,
201
+ "final_score": score,
202
+ }
203
  return {
204
  "score": score,
205
  "grader_breakdown": breakdown,