PROTHAM commited on
Commit
5834385
·
1 Parent(s): babab16

improve: hard tasks max_steps=10, fix reward gap, clearer descriptions

Browse files
graders/grader.py CHANGED
@@ -9,13 +9,22 @@ class APIGrader:
9
  try:
10
  body = json.loads(response_body)
11
  except Exception:
12
- return 0.1
13
  schema_score = self._schema_match(body, expected_schema)
 
 
14
  attempt_bonus = max(0.0, 1.0 - (attempt / max_steps) * 0.15)
15
- return round(min(1.0, max(0.0, schema_score * attempt_bonus)), 4)
16
 
17
  def _partial(self, status):
18
- mapping = {0: 0.0, 401: 0.05, 403: 0.05, 404: 0.05, 405: 0.10, 415: 0.10, 422: 0.15, 429: 0.20, 200: 0.70}
 
 
 
 
 
 
 
19
  return mapping.get(status, 0.05)
20
 
21
  def _schema_match(self, body, schema):
 
9
  try:
10
  body = json.loads(response_body)
11
  except Exception:
12
+ return 0.25
13
  schema_score = self._schema_match(body, expected_schema)
14
+ # Ensure correct status always scores higher than any error status
15
+ base_score = max(0.25, schema_score)
16
  attempt_bonus = max(0.0, 1.0 - (attempt / max_steps) * 0.15)
17
+ return round(min(1.0, max(0.0, base_score * attempt_bonus)), 4)
18
 
19
  def _partial(self, status):
20
+ mapping = {
21
+ 0: 0.0,
22
+ 401: 0.05, 403: 0.05, 404: 0.05,
23
+ 405: 0.10, 415: 0.10,
24
+ 422: 0.15,
25
+ 429: 0.20,
26
+ 200: 0.70,
27
+ }
28
  return mapping.get(status, 0.05)
29
 
30
  def _schema_match(self, body, schema):
server/api_debug_environment.py CHANGED
@@ -21,21 +21,15 @@ class APIDebugEnvironment(Environment):
21
  self._current_task = None
22
 
23
  def reset(self, task_id: str = "easy", **kwargs) -> APIObservation:
24
- # Reset the mock API state to ensure strict episode isolation
25
- try:
26
- with httpx.Client(base_url=MOCK_BASE, timeout=2.0) as http:
27
- http.post("/mock_api/_admin/reset")
28
- except Exception:
29
- pass
30
-
31
  if task_id not in TASK_REGISTRY:
32
  task_id = "easy"
33
  self._current_task = random.choice(TASK_REGISTRY[task_id])
 
34
  self._state = APIState(
35
  episode_id=f"ep_{random.randint(10000, 99999)}",
36
  step_count=0,
37
  task_id=task_id,
38
- max_steps=10,
39
  solved=False,
40
  )
41
  return APIObservation(
@@ -106,4 +100,4 @@ class APIDebugEnvironment(Environment):
106
 
107
  @property
108
  def state(self) -> APIState:
109
- return self._state
 
21
  self._current_task = None
22
 
23
  def reset(self, task_id: str = "easy", **kwargs) -> APIObservation:
 
 
 
 
 
 
 
24
  if task_id not in TASK_REGISTRY:
25
  task_id = "easy"
26
  self._current_task = random.choice(TASK_REGISTRY[task_id])
27
+ max_steps = self._current_task.get("max_steps", 5)
28
  self._state = APIState(
29
  episode_id=f"ep_{random.randint(10000, 99999)}",
30
  step_count=0,
31
  task_id=task_id,
32
+ max_steps=max_steps,
33
  solved=False,
34
  )
35
  return APIObservation(
 
100
 
101
  @property
102
  def state(self) -> APIState:
103
+ return self._state
tasks/expert.py CHANGED
@@ -11,6 +11,7 @@ EXPERT_TASKS = [
11
  },
12
  "expected_status": 200,
13
  "expected_schema": {"status": "", "cpu": 0.0, "mem": 0.0},
 
14
  },
15
  {
16
  "id": "expert_stateful_chain",
@@ -24,5 +25,6 @@ EXPERT_TASKS = [
24
  },
25
  "expected_status": 200,
26
  "expected_schema": {"status": "", "item_id": ""},
 
27
  },
28
  ]
 
11
  },
12
  "expected_status": 200,
13
  "expected_schema": {"status": "", "cpu": 0.0, "mem": 0.0},
14
+ "max_steps": 10,
15
  },
16
  {
17
  "id": "expert_stateful_chain",
 
25
  },
26
  "expected_status": 200,
27
  "expected_schema": {"status": "", "item_id": ""},
28
+ "max_steps": 10,
29
  },
30
  ]
tasks/hard.py CHANGED
@@ -1,7 +1,13 @@
1
  HARD_TASKS = [
2
  {
3
  "id": "hard_token_exchange",
4
- "description": "Access the protected resource at GET /mock_api/protected. You might need to authenticate first to get a valid token. Valid credentials are client_id 'abc' and client_secret 'xyz' at /mock_api/auth/token.",
 
 
 
 
 
 
5
  "broken_request": {
6
  "method": "GET",
7
  "url": "/mock_api/protected",
@@ -11,10 +17,15 @@ HARD_TASKS = [
11
  },
12
  "expected_status": 200,
13
  "expected_schema": {"data": ""},
 
14
  },
15
  {
16
  "id": "hard_rate_limit",
17
- "description": "Retrieve data from /mock_api/rate_limited. The server has strict rate limits. Continuously attempt to fetch until you get a successful 200 OK.",
 
 
 
 
18
  "broken_request": {
19
  "method": "GET",
20
  "url": "/mock_api/rate_limited",
@@ -24,10 +35,16 @@ HARD_TASKS = [
24
  },
25
  "expected_status": 200,
26
  "expected_schema": {"data": ""},
 
27
  },
28
  {
29
  "id": "hard_pagination",
30
- "description": "Fetch all logs from GET /mock_api/logs to get a 200 OK without more pages. The endpoint returns a cursor. Follow the cursor chain until has_more is false.",
 
 
 
 
 
31
  "broken_request": {
32
  "method": "GET",
33
  "url": "/mock_api/logs",
@@ -37,5 +54,6 @@ HARD_TASKS = [
37
  },
38
  "expected_status": 200,
39
  "expected_schema": {"items": [], "has_more": False},
 
40
  },
41
  ]
 
1
  HARD_TASKS = [
2
  {
3
  "id": "hard_token_exchange",
4
+ "description": (
5
+ "The protected endpoint needs a fresh token. "
6
+ "Step 1: POST to /mock_api/auth/token with JSON body {\"client_id\": \"abc\", \"client_secret\": \"xyz\"} "
7
+ "to get an access_token from the response. "
8
+ "Step 2: Use that token as Authorization: Bearer <token> to GET /mock_api/protected. "
9
+ "The token in the broken request is expired and will return 401."
10
+ ),
11
  "broken_request": {
12
  "method": "GET",
13
  "url": "/mock_api/protected",
 
17
  },
18
  "expected_status": 200,
19
  "expected_schema": {"data": ""},
20
+ "max_steps": 10,
21
  },
22
  {
23
  "id": "hard_rate_limit",
24
+ "description": (
25
+ "The rate_limited endpoint returns 429 after 3 requests without the X-Retry-After header. "
26
+ "When you receive a 429, add the header X-Retry-After: 2 to your next request. "
27
+ "The response body on 429 contains Retry-After hint in headers."
28
+ ),
29
  "broken_request": {
30
  "method": "GET",
31
  "url": "/mock_api/rate_limited",
 
35
  },
36
  "expected_status": 200,
37
  "expected_schema": {"data": ""},
38
+ "max_steps": 10,
39
  },
40
  {
41
  "id": "hard_pagination",
42
+ "description": (
43
+ "GET /mock_api/logs returns the first page with next_cursor and has_more fields. "
44
+ "Pass cursor=<next_cursor> as a query param to get the next page. "
45
+ "Keep following the cursor chain until has_more is false. "
46
+ "The final page has has_more=false and no next_cursor."
47
+ ),
48
  "broken_request": {
49
  "method": "GET",
50
  "url": "/mock_api/logs",
 
54
  },
55
  "expected_status": 200,
56
  "expected_schema": {"items": [], "has_more": False},
57
+ "max_steps": 10,
58
  },
59
  ]