nadellaroshni commited on
Commit
8034313
·
1 Parent(s): 2d35d5a
Files changed (4) hide show
  1. env/models.py +11 -0
  2. env/task_catalog.py +55 -0
  3. openenv.yaml +22 -3
  4. server/app.py +9 -1
env/models.py CHANGED
@@ -155,6 +155,7 @@ class StepResult(BaseModel):
155
 
156
  class ResetRequest(BaseModel):
157
  difficulty: Difficulty = Difficulty.MEDIUM
 
158
  audio_path: Optional[str] = None
159
  transcript_override: Optional[str] = None
160
 
@@ -201,3 +202,13 @@ class PlanResponse(BaseModel):
201
  breakdown: Dict[str, float]
202
  summary: str
203
  final_board: str
 
 
 
 
 
 
 
 
 
 
 
155
 
156
  class ResetRequest(BaseModel):
157
  difficulty: Difficulty = Difficulty.MEDIUM
158
+ task: Optional[str] = None
159
  audio_path: Optional[str] = None
160
  transcript_override: Optional[str] = None
161
 
 
202
  breakdown: Dict[str, float]
203
  summary: str
204
  final_board: str
205
+
206
+
207
+ class TaskDescriptor(BaseModel):
208
+ id: str
209
+ name: str
210
+ difficulty: Difficulty
211
+ objective: str
212
+ grader: str
213
+ score_range: str = "[0.0, 1.0]"
214
+ deterministic: bool = True
env/task_catalog.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Explicit task catalog for validator and API task discovery.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from .models import Difficulty, TaskDescriptor
8
+
9
+
10
+ TASK_CATALOG: list[TaskDescriptor] = [
11
+ TaskDescriptor(
12
+ id="easy",
13
+ name="easy",
14
+ difficulty=Difficulty.EASY,
15
+ objective=(
16
+ "Create the best sprint plan from a static backlog with fixed team capacity "
17
+ "and fixed deadlines."
18
+ ),
19
+ grader="env.graders.grade",
20
+ ),
21
+ TaskDescriptor(
22
+ id="medium",
23
+ name="medium",
24
+ difficulty=Difficulty.MEDIUM,
25
+ objective=(
26
+ "Revise the sprint plan after one mid-sprint disruption such as urgent work "
27
+ "or a developer capacity loss."
28
+ ),
29
+ grader="env.graders.grade",
30
+ ),
31
+ TaskDescriptor(
32
+ id="hard",
33
+ name="hard",
34
+ difficulty=Difficulty.HARD,
35
+ objective=(
36
+ "Repeatedly re-plan under multiple disruptions including added work, "
37
+ "capacity changes, and dependency shifts while preserving feasibility."
38
+ ),
39
+ grader="env.graders.grade",
40
+ ),
41
+ ]
42
+
43
+
44
+ def get_task_catalog() -> list[TaskDescriptor]:
45
+ return TASK_CATALOG
46
+
47
+
48
+ def resolve_task_name(name: str | None) -> Difficulty | None:
49
+ if not name:
50
+ return None
51
+ normalized = name.strip().lower()
52
+ for task in TASK_CATALOG:
53
+ if task.id == normalized or task.name == normalized:
54
+ return task.difficulty
55
+ return None
openenv.yaml CHANGED
@@ -7,9 +7,27 @@ version: "1.0.0"
7
  entrypoint: env.environment:SprintEnv
8
 
9
  tasks:
10
- - easy
11
- - medium
12
- - hard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  environment:
15
  max_steps: 20
@@ -37,6 +55,7 @@ dependencies:
37
  server:
38
  host: 0.0.0.0
39
  port: 7860
 
40
  endpoint_reset: /reset
41
  endpoint_step: /step
42
  endpoint_state: /state
 
7
  entrypoint: env.environment:SprintEnv
8
 
9
  tasks:
10
+ - id: easy
11
+ name: easy
12
+ difficulty: easy
13
+ objective: Create the best sprint plan from a static backlog with fixed capacity and deadlines.
14
+ grader: env.graders.grade
15
+ score_range: [0.0, 1.0]
16
+ deterministic: true
17
+ - id: medium
18
+ name: medium
19
+ difficulty: medium
20
+ objective: Revise the sprint plan once after a single mid-sprint disruption.
21
+ grader: env.graders.grade
22
+ score_range: [0.0, 1.0]
23
+ deterministic: true
24
+ - id: hard
25
+ name: hard
26
+ difficulty: hard
27
+ objective: Re-plan repeatedly under multiple disruptions while preserving feasibility and value.
28
+ grader: env.graders.grade
29
+ score_range: [0.0, 1.0]
30
+ deterministic: true
31
 
32
  environment:
33
  max_steps: 20
 
55
  server:
56
  host: 0.0.0.0
57
  port: 7860
58
+ endpoint_tasks: /tasks
59
  endpoint_reset: /reset
60
  endpoint_step: /step
61
  endpoint_state: /state
server/app.py CHANGED
@@ -23,7 +23,9 @@ from env.models import (
23
  ResetRequest,
24
  StepRequest,
25
  StepResult,
 
26
  )
 
27
  from planner import generate_plan
28
 
29
  logger = logging.getLogger(__name__)
@@ -60,13 +62,19 @@ def health():
60
  return {"status": "ok", "env_ready": env is not None}
61
 
62
 
 
 
 
 
 
63
  @app.post("/reset", response_model=Observation)
64
  def reset(request: ResetRequest = ResetRequest()):
65
  global env
66
  if env is None:
67
  raise HTTPException(500, "Environment not initialised")
 
68
  return env.reset(
69
- difficulty=request.difficulty,
70
  audio_path=request.audio_path,
71
  transcript_override=request.transcript_override,
72
  )
 
23
  ResetRequest,
24
  StepRequest,
25
  StepResult,
26
+ TaskDescriptor,
27
  )
28
+ from env.task_catalog import get_task_catalog, resolve_task_name
29
  from planner import generate_plan
30
 
31
  logger = logging.getLogger(__name__)
 
62
  return {"status": "ok", "env_ready": env is not None}
63
 
64
 
65
+ @app.get("/tasks", response_model=list[TaskDescriptor])
66
+ def list_tasks():
67
+ return get_task_catalog()
68
+
69
+
70
  @app.post("/reset", response_model=Observation)
71
  def reset(request: ResetRequest = ResetRequest()):
72
  global env
73
  if env is None:
74
  raise HTTPException(500, "Environment not initialised")
75
+ requested_difficulty = resolve_task_name(request.task) or request.difficulty
76
  return env.reset(
77
+ difficulty=requested_difficulty,
78
  audio_path=request.audio_path,
79
  transcript_override=request.transcript_override,
80
  )