nadellaroshni commited on
Commit
2646de7
·
1 Parent(s): 4400763

Add Docker + OpenEnv config updates and remaining changes

Browse files
Files changed (4) hide show
  1. README.md +100 -179
  2. env/extraction.py +2 -2
  3. planner.py +13 -6
  4. requirements-train.txt +3 -0
README.md CHANGED
@@ -3,73 +3,56 @@ title: Smart Sprint Planner
3
  emoji: "🗂️"
4
  colorFrom: blue
5
  colorTo: green
6
- # Force rebuild - ensures latest code is deployed
7
  sdk: docker
8
  app_port: 7860
9
  ---
10
 
11
  # Smart Sprint Planner
12
 
13
- Real-world OpenEnv environment for agile sprint planning and dynamic replanning.
14
 
15
  Core pipeline:
16
- `audio or transcript -> extraction -> JIRA-style tickets -> developer assignments -> dynamic disruptions -> reward and grading`
17
 
18
- This repository is aligned to the Round 1 competition requirements captured in [context_scaler.txt](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/context_scaler.txt).
19
 
20
- ## Environment Summary
21
 
22
- The environment simulates a real planning workflow an engineering manager, scrum lead, or delivery lead would actually perform:
 
 
 
23
 
24
- - convert planning discussion into structured tasks
25
- - assign work under team capacity constraints
26
- - respond to urgent work, capacity loss, and dependency changes
27
- - maximize completion, timeliness, workload balance, and adaptability
28
 
29
- This is intended as a real-world planning and replanning environment, not a toy game.
30
-
31
- ## Tasks And Difficulty
32
 
33
  There are 3 graded tasks:
34
 
35
- - `easy`
36
- Static sprint planning. Fixed backlog, fixed capacity, fixed deadlines.
37
- - `medium`
38
- One disruption event. Usually urgent work or a developer capacity loss.
39
- - `hard`
40
- Multiple disruptions over time. New work, dependency shifts, and changing capacity.
41
-
42
- Difficulty represents volatility, not just more tickets.
43
-
44
- ## Project Flow
45
-
46
- 1. [env/transcription.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/transcription.py)
47
- Handles audio-to-text or accepts provided transcript text.
48
- 2. [env/extraction.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/extraction.py)
49
- Extracts structured work items with an LLM or deterministic fallback logic.
50
- 3. [env/jira.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/jira.py)
51
- Converts extracted items into JIRA-style sprint tickets.
52
- 4. [env/environment.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/environment.py)
53
- Implements `reset()`, `step()`, and `state()` with dynamic event handling.
54
- 5. [env/graders.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/graders.py)
55
- Computes dense rewards and final deterministic grading in `[0.0, 1.0]`.
56
- 6. [planner.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/planner.py)
57
- Runs the full end-to-end pipeline and returns assignment recommendations.
58
-
59
- ## Observation And Action Space
60
-
61
- Observation includes:
62
-
63
- - meeting text
64
- - extracted work items
65
- - active JIRA tickets
66
- - developer pool
67
- - completed task ids
68
- - sprint day
69
- - metrics and event history
70
- - pending and recent disruption signals
71
-
72
- Action is one assignment:
73
 
74
  ```json
75
  {
@@ -78,172 +61,114 @@ Action is one assignment:
78
  }
79
  ```
80
 
81
- ## Extraction Schema
82
-
83
- Each extracted item can include:
84
-
85
- - `task`
86
- - `description`
87
- - `deadline`
88
- - `priority`
89
- - `category`
90
- - `tags`
91
- - `acceptance_criteria`
92
- - `dependency_hints`
93
- - `owner_hint`
94
- - `urgency_reason`
95
- - `raw_text`
96
 
97
- LLM extraction uses the OpenAI client when credentials are available. Otherwise the system uses a deterministic rule-based fallback for offline reproducibility.
98
 
99
- ## Reward And Grading
 
 
 
 
 
100
 
101
- Dense step rewards include:
102
 
103
- - on-time completion
104
- - specialization or skill-match reward
105
- - priority-aware completion reward
106
- - penalties for invalid, blocked, and over-capacity actions
107
- - adaptation reward for disruption-created work
108
- - future-feasibility shaping for preserving replanning options
109
 
110
- Final grading combines:
 
 
 
 
 
 
 
111
 
112
- - completion rate
113
- - on-time rate
114
- - extraction quality
115
- - workload balance
116
- - efficiency
117
- - adaptability
118
 
119
- All final scores are normalized to `[0.0, 1.0]`.
 
 
 
 
 
 
 
120
 
121
  ## Baseline Inference
122
 
123
- The required root-level baseline script is [inference.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/inference.py).
124
 
125
  It:
126
 
127
- - uses the OpenAI client for LLM calls
128
- - reads `API_BASE_URL`, `MODEL_NAME`, and `API_KEY`
129
- - also accepts `HF_TOKEN` when `API_KEY` is not set
130
- - always sends LLM traffic through the configured `API_BASE_URL`
131
- - emits strict competition stdout lines:
132
- - `[START]`
133
- - `[STEP]`
134
- - `[END]`
135
 
136
  Example:
137
 
138
  ```bash
139
- API_BASE_URL=https://router.huggingface.co/v1 API_KEY=... python inference.py
140
- ```
141
-
142
- Run all tasks:
143
-
144
- ```bash
145
- API_BASE_URL=https://router.huggingface.co/v1 API_KEY=... python inference.py
146
  ```
147
 
148
- Expected submission behavior:
149
-
150
- - the script makes live proxy-backed LLM calls for all three tasks
151
- - task names emitted in logs are `easy`, `medium`, and `hard`
152
- - API failures are surfaced instead of being silently swallowed
153
-
154
- ## Learned Planner
155
 
156
- The learned planner is trained separately and is not required for the baseline script.
157
 
158
- - training entrypoint: [train.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/train.py)
159
- - evaluation entrypoint: [eval.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/eval.py)
160
- - strongest checkpoint: `checkpoints/best`
 
 
 
161
 
162
- Current held-out dataset-eval comparison for the strongest checkpoint:
163
 
164
- - Heuristic: `0.893`
165
- - DDQN: `0.897`
166
 
167
- On the richer held-out split, the learned DDQN now slightly outperforms the heuristic overall and on `hard`.
168
-
169
- Train:
170
 
171
  ```bash
172
- python train.py --episodes 400
173
- ```
174
-
175
- Evaluate:
176
-
177
- ```bash
178
- python eval.py --checkpoint checkpoints/best --scenario-source dataset-eval
179
  ```
180
 
181
- ## Full Pipeline
182
-
183
- The full product-facing path is exposed through [planner.py](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/planner.py) and `POST /plan`.
184
-
185
- Run locally from transcript:
186
 
187
- ```bash
188
- python planner.py --transcript "Fix the checkout bug today, then finish analytics after auth." --difficulty medium --strategy auto
 
 
189
  ```
190
 
191
- `auto` prefers the trained DDQN checkpoint when `checkpoints/best` exists, and falls back to heuristic otherwise.
192
-
193
- ## API Server
194
-
195
- Start the server:
196
 
197
  ```bash
198
- uvicorn server.app:app --reload --port 7860
199
  ```
200
 
201
- Endpoints:
202
-
203
- - `GET /health`
204
- - `POST /reset`
205
- - `POST /step`
206
- - `GET /state`
207
- - `GET /render`
208
- - `GET /grade`
209
- - `POST /plan`
210
-
211
- ## Setup
212
 
213
  ```bash
214
- python -m venv venv
215
- source venv/bin/activate
216
- pip install -r requirements.txt
217
- ```
218
-
219
- Windows:
220
-
221
- ```powershell
222
- python -m venv venv
223
- venv\Scripts\activate
224
- pip install -r requirements.txt
225
  ```
226
 
227
- ## Validation And Tests
228
-
229
- Run tests:
230
 
231
  ```bash
232
  python -m pytest tests -v
233
  ```
234
 
235
- Run OpenEnv validation:
236
 
237
- ```powershell
238
- .\whisper_env\Scripts\openenv.exe validate
239
  ```
240
 
241
- Current local status:
242
-
243
- - the main automated tests live in `tests/`
244
- - `openenv validate` should be run from an environment with `openenv-core` installed
245
- - baseline inference is submission-oriented and requires proxy credentials
246
-
247
  ## Docker
248
 
249
  Build:
@@ -258,13 +183,9 @@ Run:
258
  docker run -p 7860:7860 smart-sprint-planner
259
  ```
260
 
261
- ## Metadata
262
-
263
- Environment metadata lives in [openenv.yaml](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/openenv.yaml).
264
-
265
- Before final submission, the remaining non-code checklist is:
266
 
267
- 1. verify Docker builds on the target machine
268
- 2. verify the Hugging Face Space responds with `200`
269
- 3. keep the root `inference.py` output unchanged
270
- 4. submit with `checkpoints/best` included if you want `auto` to use DDQN
 
3
  emoji: "🗂️"
4
  colorFrom: blue
5
  colorTo: green
 
6
  sdk: docker
7
  app_port: 7860
8
  ---
9
 
10
  # Smart Sprint Planner
11
 
12
+ Smart Sprint Planner is an OpenEnv environment for a real software-delivery task: planning and replanning an engineering sprint from meeting context, backlog pressure, team capacity, and changing sprint conditions.
13
 
14
  Core pipeline:
15
+ `audio or transcript -> extracted action items -> JIRA-style tickets -> developer assignments -> disruptions -> grading`
16
 
17
+ ## Why This Environment
18
 
19
+ This environment simulates the kind of planning work an engineering manager, scrum lead, or delivery owner actually performs:
20
 
21
+ - convert planning discussion into structured work
22
+ - assign tickets under capacity and specialization constraints
23
+ - react to urgent work, lost capacity, and dependency changes
24
+ - preserve feasibility while maximizing delivery value
25
 
26
+ It is deliberately not a toy game. The task is operational planning under uncertainty.
 
 
 
27
 
28
+ ## Tasks
 
 
29
 
30
  There are 3 graded tasks:
31
 
32
+ | Task | Difficulty | Max Steps | Description |
33
+ |------|------------|-----------|-------------|
34
+ | `easy` | Easy | 10 | Static sprint planning with fixed backlog and no disruptions |
35
+ | `medium` | Medium | 15 | Replanning after one mid-sprint disruption |
36
+ | `hard` | Hard | 20 | Multi-disruption planning with shifting capacity and dependencies |
37
+
38
+ ## Observation Space
39
+
40
+ Each `reset()` and `step()` returns a typed [`Observation`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/models.py) containing:
41
+
42
+ - `meeting_text`
43
+ - `extracted_items`
44
+ - `jira_tickets`
45
+ - `developers`
46
+ - `completed_task_ids`
47
+ - `sprint_day`
48
+ - `metrics`
49
+ - `difficulty`
50
+ - `recent_events`
51
+ - `pending_events`
52
+
53
+ ## Action Space
54
+
55
+ The action is a typed [`Action`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/models.py) with one assignment:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  ```json
58
  {
 
61
  }
62
  ```
63
 
64
+ ## Reward Design
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ Dense reward signals are used throughout the trajectory:
67
 
68
+ - positive reward for on-time completion
69
+ - positive reward for skill-matched assignment
70
+ - positive reward for high-priority completion
71
+ - adaptation reward for disruption-created work
72
+ - penalties for invalid ids, blocked work, and over-capacity assignments
73
+ - episode bonus for full completion, balance, efficiency, and disruption handling
74
 
75
+ Final graders return normalized scores in `[0.0, 1.0]`.
76
 
77
+ ## Project Structure
 
 
 
 
 
78
 
79
+ - [`env/models.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/models.py): typed Pydantic contracts
80
+ - [`env/tasks.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/tasks.py): scenario registry and fallback datasets
81
+ - [`env/extraction.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/extraction.py): transcript-to-work extraction
82
+ - [`env/jira.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/jira.py): JIRA-style ticket generation
83
+ - [`env/environment.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/environment.py): `reset()`, `step()`, `state()`
84
+ - [`env/graders.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/env/graders.py): dense reward and final task graders
85
+ - [`server/app.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/server/app.py): FastAPI runtime
86
+ - [`inference.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/inference.py): baseline OpenAI-client inference script
87
 
88
+ ## API Endpoints
 
 
 
 
 
89
 
90
+ - `GET /health`
91
+ - `GET /tasks`
92
+ - `POST /reset`
93
+ - `POST /step`
94
+ - `GET /state`
95
+ - `GET /render`
96
+ - `GET /grade`
97
+ - `POST /plan`
98
 
99
  ## Baseline Inference
100
 
101
+ The required root-level baseline script is [`inference.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/inference.py).
102
 
103
  It:
104
 
105
+ - uses the OpenAI client for all LLM calls
106
+ - reads `API_BASE_URL`, `MODEL_NAME`, and `HF_TOKEN`
107
+ - also accepts `API_KEY` or `OPENAI_API_KEY` as fallbacks for local testing
108
+ - emits only the required `[START]`, `[STEP]`, and `[END]` log lines
109
+ - uses an LLM to choose among valid assignment candidates at every step
 
 
 
110
 
111
  Example:
112
 
113
  ```bash
114
+ API_BASE_URL=https://router.huggingface.co/v1 MODEL_NAME=Qwen/Qwen2.5-72B-Instruct HF_TOKEN=... python inference.py
 
 
 
 
 
 
115
  ```
116
 
117
+ ## Baseline Scores
 
 
 
 
 
 
118
 
119
+ Current deterministic baseline scores from the built-in heuristic policy on the default scenarios:
120
 
121
+ | Task | Score |
122
+ |------|-------|
123
+ | `easy` | `0.833` |
124
+ | `medium` | `0.734` |
125
+ | `hard` | `0.761` |
126
+ | **overall mean** | **`0.776`** |
127
 
128
+ These numbers are also reflected in [`openenv.yaml`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/openenv.yaml).
129
 
130
+ ## Local Usage
 
131
 
132
+ ### Setup
 
 
133
 
134
  ```bash
135
+ python -m venv .venv
136
+ source .venv/bin/activate
137
+ pip install -r requirements.txt
 
 
 
 
138
  ```
139
 
140
+ Windows:
 
 
 
 
141
 
142
+ ```powershell
143
+ python -m venv .venv
144
+ .venv\Scripts\activate
145
+ pip install -r requirements.txt
146
  ```
147
 
148
+ ### Run Server
 
 
 
 
149
 
150
  ```bash
151
+ uvicorn server.app:app --host 0.0.0.0 --port 7860
152
  ```
153
 
154
+ ### Run Planner From Transcript
 
 
 
 
 
 
 
 
 
 
155
 
156
  ```bash
157
+ python planner.py --difficulty medium --strategy heuristic --transcript "Fix checkout today, then finish analytics after auth."
 
 
 
 
 
 
 
 
 
 
158
  ```
159
 
160
+ ### Run Tests
 
 
161
 
162
  ```bash
163
  python -m pytest tests -v
164
  ```
165
 
166
+ ### Run OpenEnv Validation
167
 
168
+ ```bash
169
+ openenv validate
170
  ```
171
 
 
 
 
 
 
 
172
  ## Docker
173
 
174
  Build:
 
183
  docker run -p 7860:7860 smart-sprint-planner
184
  ```
185
 
186
+ ## Submission Notes
 
 
 
 
187
 
188
+ - keep [`inference.py`](C:/Users/ASUS/Documents/GitHub/smart_sprint_planner/inference.py) at the repo root
189
+ - do not change the `[START]`, `[STEP]`, `[END]` stdout format
190
+ - ensure your Hugging Face Space responds to `POST /reset`
191
+ - ensure `openenv validate` passes before submission
env/extraction.py CHANGED
@@ -118,7 +118,7 @@ def _get_client():
118
 
119
  # CRITICAL: Use ONLY the validator-injected credentials
120
  # NO fallbacks - if these are missing, gracefully degrade to unavailable
121
- api_key = os.environ.get("API_KEY") or os.environ.get("HF_TOKEN")
122
  api_base_url = os.environ.get("API_BASE_URL")
123
 
124
  if not api_key or not api_base_url:
@@ -150,7 +150,7 @@ def _call_llm(transcript: str) -> List[dict]:
150
  if client == "unavailable":
151
  raise RuntimeError("LLM client not available")
152
 
153
- model = os.getenv("MODEL_NAME", "gpt-4o-mini")
154
 
155
  if hasattr(client, "responses"):
156
  response = client.responses.create(
 
118
 
119
  # CRITICAL: Use ONLY the validator-injected credentials
120
  # NO fallbacks - if these are missing, gracefully degrade to unavailable
121
+ api_key = os.environ.get("HF_TOKEN") or os.environ.get("API_KEY") or os.environ.get("OPENAI_API_KEY")
122
  api_base_url = os.environ.get("API_BASE_URL")
123
 
124
  if not api_key or not api_base_url:
 
150
  if client == "unavailable":
151
  raise RuntimeError("LLM client not available")
152
 
153
+ model = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
154
 
155
  if hasattr(client, "responses"):
156
  response = client.responses.create(
planner.py CHANGED
@@ -7,9 +7,8 @@ from __future__ import annotations
7
  import argparse
8
  import json
9
  from pathlib import Path
10
- from typing import Optional, Tuple
11
 
12
- from agent.dqn_agent import DDQNAgent
13
  from agent.heuristic_agent import HeuristicAgent
14
  from env.environment import SprintEnv
15
  from env.graders import grade
@@ -21,6 +20,9 @@ from env.models import (
21
  PlanResponse,
22
  )
23
 
 
 
 
24
 
25
  def _load_agent(strategy: str, checkpoint: Optional[str]) -> Tuple[object, str]:
26
  normalized = strategy.lower()
@@ -30,16 +32,21 @@ def _load_agent(strategy: str, checkpoint: Optional[str]) -> Tuple[object, str]:
30
  if normalized == "ddqn":
31
  ckpt = checkpoint or "checkpoints/best"
32
  if (Path(ckpt) / "online.pkl").exists():
33
- agent = DDQNAgent()
34
- agent.load(ckpt)
35
- return agent, "ddqn"
 
 
 
 
 
36
  normalized = "heuristic"
37
 
38
  return HeuristicAgent(), normalized
39
 
40
 
41
  def _choose_action(agent: object, obs: Observation) -> Optional[Action]:
42
- if isinstance(agent, DDQNAgent):
43
  return agent.act(obs, deterministic=True)
44
  if isinstance(agent, HeuristicAgent):
45
  return agent.act(obs)
 
7
  import argparse
8
  import json
9
  from pathlib import Path
10
+ from typing import TYPE_CHECKING, Optional, Tuple
11
 
 
12
  from agent.heuristic_agent import HeuristicAgent
13
  from env.environment import SprintEnv
14
  from env.graders import grade
 
20
  PlanResponse,
21
  )
22
 
23
+ if TYPE_CHECKING:
24
+ from agent.dqn_agent import DDQNAgent
25
+
26
 
27
  def _load_agent(strategy: str, checkpoint: Optional[str]) -> Tuple[object, str]:
28
  normalized = strategy.lower()
 
32
  if normalized == "ddqn":
33
  ckpt = checkpoint or "checkpoints/best"
34
  if (Path(ckpt) / "online.pkl").exists():
35
+ try:
36
+ from agent.dqn_agent import DDQNAgent
37
+ except ImportError:
38
+ normalized = "heuristic"
39
+ else:
40
+ agent = DDQNAgent()
41
+ agent.load(ckpt)
42
+ return agent, "ddqn"
43
  normalized = "heuristic"
44
 
45
  return HeuristicAgent(), normalized
46
 
47
 
48
  def _choose_action(agent: object, obs: Observation) -> Optional[Action]:
49
+ if agent.__class__.__name__ == "DDQNAgent":
50
  return agent.act(obs, deterministic=True)
51
  if isinstance(agent, HeuristicAgent):
52
  return agent.act(obs)
requirements-train.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ -r requirements.txt
2
+ numpy>=1.26,<3
3
+ torch==2.6.0