pvs333 commited on
Commit
bc4fcc7
·
1 Parent(s): 0681dc4

new rewards

Browse files
__pycache__/models.cpython-314.pyc CHANGED
Binary files a/__pycache__/models.cpython-314.pyc and b/__pycache__/models.cpython-314.pyc differ
 
models.py CHANGED
@@ -99,7 +99,7 @@ class SupergamesObservation(Observation):
99
 
100
  class StepResult(BaseModel):
101
  observation: SupergamesObservation
102
- reward: float = Field(..., ge = 0.0, le=1.0)
103
  done: bool
104
  info: Optional[Dict[str, Any]] = None
105
 
 
99
 
100
  class StepResult(BaseModel):
101
  observation: SupergamesObservation
102
+ reward: float = Field(..., ge=-100.0, le=100.0)
103
  done: bool
104
  info: Optional[Dict[str, Any]] = None
105
 
server/__pycache__/environment.cpython-314.pyc CHANGED
Binary files a/server/__pycache__/environment.cpython-314.pyc and b/server/__pycache__/environment.cpython-314.pyc differ
 
server/environment.py CHANGED
@@ -32,6 +32,8 @@ class SupergamesEnvironment(Environment):
32
  """Environment for staffing and sprint allocation across Supergames tasks."""
33
 
34
  SUPPORTS_CONCURRENT_SESSIONS: bool = True
 
 
35
 
36
  def __init__(self):
37
  self.stateData = State(episode_id=str(uuid4()), step_count=0)
@@ -107,18 +109,65 @@ class SupergamesEnvironment(Environment):
107
 
108
  return summary
109
 
110
- def computeReward(self, sprintRevenue: float) -> float:
111
- if not self.done:
112
- averageOptimal = self.estimatedOptimalRevenue / self.totalSteps
113
- return round(min(1.0, max(0.0, sprintRevenue / averageOptimal)), 4)
114
 
115
- grader = TASKS[self.taskId]["grade"]
116
- if self.taskId == 1:
117
- agentImpact = sum(item.revenueImpact for item in self.completedItems)
118
- return float(grader(agentImpact, self.initialWorkQueue, self.initialStaffPool))
119
- if self.taskId in (2, 3):
120
- return float(grader(self.cumulativeRevenue, self.estimatedOptimalRevenue))
121
- return float(grader(self.cumulativeRevenue, self.estimatedOptimalRevenue, self.crisisResolved))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  def reset(self, task_id: int = 1, seed: int = 42) -> SupergamesObservation:
124
  if task_id not in TASKS:
@@ -159,7 +208,7 @@ class SupergamesEnvironment(Environment):
159
 
160
  def step(self, action: SupergamesAction) -> SupergamesObservation:
161
  if self.done:
162
- return self.buildObservation(reward=self.computeReward(0.0))
163
 
164
  self.stateData.step_count += 1
165
  reasoning = action.reasoning.strip()
@@ -190,7 +239,7 @@ class SupergamesEnvironment(Environment):
190
  self.crisisResolved = True
191
 
192
  self.done = self.stateData.step_count >= self.totalSteps
193
- reward = self.computeReward(sprintRevenue)
194
 
195
  obs = self.buildObservation(reward=reward)
196
  obs.metadata.update(
 
32
  """Environment for staffing and sprint allocation across Supergames tasks."""
33
 
34
  SUPPORTS_CONCURRENT_SESSIONS: bool = True
35
+ MIN_REWARD: float = -100.0
36
+ MAX_REWARD: float = 100.0
37
 
38
  def __init__(self):
39
  self.stateData = State(episode_id=str(uuid4()), step_count=0)
 
109
 
110
  return summary
111
 
112
+ def _clampReward(self, reward: float) -> float:
113
+ return round(min(self.MAX_REWARD, max(self.MIN_REWARD, reward)), 2)
 
 
114
 
115
+ @staticmethod
116
+ def _delayImpactPoints(item: WorkItem) -> float:
117
+ if item.impactDelay == 0:
118
+ return 45.0
119
+ if item.impactDelay == 1:
120
+ return 25.0
121
+ return 10.0
122
+
123
+ @staticmethod
124
+ def _completedItemPoints(item: WorkItem) -> float:
125
+ severityPoints = int(item.severity) * 3.0
126
+ revenuePoints = min(20.0, item.revenueImpact / 20.0)
127
+ churnPoints = item.churnReduction * 40.0
128
+ return (
129
+ SupergamesEnvironment._delayImpactPoints(item)
130
+ + severityPoints
131
+ + revenuePoints
132
+ + churnPoints
133
+ )
134
+
135
+ def computeReward(
136
+ self,
137
+ sprintRevenue: float,
138
+ completedItems: List[WorkItem] | None = None,
139
+ message: str = "ok",
140
+ ) -> float:
141
+ completedItems = completedItems or []
142
+
143
+ if message.startswith("Overallocation"):
144
+ return -70.0
145
+ if message.startswith("Unknown work item"):
146
+ return -60.0
147
+
148
+ reward = min(35.0, sprintRevenue / 100_000.0)
149
+ reward += sum(self._completedItemPoints(item) for item in completedItems)
150
+
151
+ unresolvedPenalty = 0.0
152
+ for item in self.workQueue:
153
+ if item.workType.value != "bug":
154
+ continue
155
+ if int(item.severity) == 5:
156
+ unresolvedPenalty += 18.0
157
+ elif int(item.severity) == 4:
158
+ unresolvedPenalty += 10.0
159
+ reward -= unresolvedPenalty
160
+
161
+ churnPenalty = sum(max(0.0, game.churnMult - 1.0) * 40.0 for game in self.games)
162
+ reward -= churnPenalty
163
+
164
+ if self.done:
165
+ if not any(item.workType.value == "bug" and int(item.severity) >= 4 for item in self.workQueue):
166
+ reward += 15.0
167
+ if self.taskId == 4:
168
+ reward += 20.0 if self.crisisResolved else -40.0
169
+
170
+ return self._clampReward(reward)
171
 
172
  def reset(self, task_id: int = 1, seed: int = 42) -> SupergamesObservation:
173
  if task_id not in TASKS:
 
208
 
209
  def step(self, action: SupergamesAction) -> SupergamesObservation:
210
  if self.done:
211
+ return self.buildObservation(reward=0.0)
212
 
213
  self.stateData.step_count += 1
214
  reasoning = action.reasoning.strip()
 
239
  self.crisisResolved = True
240
 
241
  self.done = self.stateData.step_count >= self.totalSteps
242
+ reward = self.computeReward(sprintRevenue, completedItems, message)
243
 
244
  obs = self.buildObservation(reward=reward)
245
  obs.metadata.update(
train_grpo_supergames.ipynb CHANGED
@@ -319,24 +319,29 @@
319
  " return actions, matched_plan_shape\n",
320
  "\n",
321
  "\n",
322
- "def estimate_revenue_upper_bound(\n",
323
- " games: List[Game],\n",
324
- " work_queue: List[WorkItem],\n",
325
- " total_steps: int,\n",
326
- ") -> float:\n",
327
- " base_revenue = sum(game.monthlyRevenue for game in games) * total_steps\n",
328
- " impact_bound = 0.0\n",
329
- " for item in work_queue:\n",
330
- " active_sprints = max(0, total_steps - item.impactDelay)\n",
331
- " impact_bound += item.revenueImpact * (active_sprints / max(1, total_steps))\n",
332
- " return max(1.0, round(base_revenue + impact_bound, 2))\n",
 
 
 
 
 
 
333
  "\n",
334
  "\n",
335
  "def rollout_plan(completion: Any, difficulty: str, task_seed: int) -> Dict[str, Any]:\n",
336
  " games, work_queue, staff_pool, total_steps, _goal = generate_task(difficulty, seed=int(task_seed))\n",
337
- " all_items = copy.deepcopy(work_queue)\n",
338
- " pending_crisis_items = [item for item in all_items if item.crisis]\n",
339
- " active_work_queue = [item for item in all_items if not item.crisis]\n",
340
  " games = copy.deepcopy(games)\n",
341
  " staff_pool = copy.deepcopy(staff_pool)\n",
342
  "\n",
@@ -344,7 +349,7 @@
344
  " actions, matched_plan_shape = parse_sprint_actions(completion, total_steps)\n",
345
  " except Exception:\n",
346
  " return {\n",
347
- " \"reward\": -0.5,\n",
348
  " \"valid_json\": False,\n",
349
  " \"matched_plan_shape\": False,\n",
350
  " \"cumulative_revenue\": 0.0,\n",
@@ -353,7 +358,8 @@
353
  "\n",
354
  " cumulative_revenue = 0.0\n",
355
  " messages = []\n",
356
- " completed_count = 0\n",
 
357
  "\n",
358
  " for sprint_idx in range(1, total_steps + 1):\n",
359
  " if sprint_idx >= 2 and pending_crisis_items:\n",
@@ -368,20 +374,35 @@
368
  " sprint_idx,\n",
369
  " )\n",
370
  " cumulative_revenue += sprint_revenue\n",
371
- " completed_count += len(completed_items)\n",
372
  " messages.append(message)\n",
373
  "\n",
374
- " upper_bound = estimate_revenue_upper_bound(games, all_items, total_steps)\n",
375
- " revenue_score = max(0.0, min(1.0, cumulative_revenue / upper_bound))\n",
376
- " format_bonus = 0.05 if matched_plan_shape else 0.0\n",
377
- " completion_bonus = min(0.10, completed_count * 0.01)\n",
378
- " reward = revenue_score + format_bonus + completion_bonus\n",
 
 
 
 
 
379
  "\n",
380
- " if any(message.startswith(\"Overallocation\") or message.startswith(\"Unknown work item\") for message in messages):\n",
381
- " reward -= 0.25\n",
 
 
 
 
 
 
 
 
 
 
 
382
  "\n",
383
  " return {\n",
384
- " \"reward\": float(max(-0.5, min(1.2, reward))),\n",
385
  " \"valid_json\": True,\n",
386
  " \"matched_plan_shape\": matched_plan_shape,\n",
387
  " \"cumulative_revenue\": cumulative_revenue,\n",
 
319
  " return actions, matched_plan_shape\n",
320
  "\n",
321
  "\n",
322
+ "def clamp_reward(reward: float) -> float:\n",
323
+ " return round(min(100.0, max(-100.0, reward)), 2)\n",
324
+ "\n",
325
+ "\n",
326
+ "def delay_impact_points(item: WorkItem) -> float:\n",
327
+ " if item.impactDelay == 0:\n",
328
+ " return 45.0\n",
329
+ " if item.impactDelay == 1:\n",
330
+ " return 25.0\n",
331
+ " return 10.0\n",
332
+ "\n",
333
+ "\n",
334
+ "def completed_item_points(item: WorkItem) -> float:\n",
335
+ " severity_points = int(item.severity) * 3.0\n",
336
+ " revenue_points = min(20.0, item.revenueImpact / 20.0)\n",
337
+ " churn_points = item.churnReduction * 40.0\n",
338
+ " return delay_impact_points(item) + severity_points + revenue_points + churn_points\n",
339
  "\n",
340
  "\n",
341
  "def rollout_plan(completion: Any, difficulty: str, task_seed: int) -> Dict[str, Any]:\n",
342
  " games, work_queue, staff_pool, total_steps, _goal = generate_task(difficulty, seed=int(task_seed))\n",
343
+ " pending_crisis_items = [copy.deepcopy(item) for item in work_queue if item.crisis]\n",
344
+ " active_work_queue = [copy.deepcopy(item) for item in work_queue if not item.crisis]\n",
 
345
  " games = copy.deepcopy(games)\n",
346
  " staff_pool = copy.deepcopy(staff_pool)\n",
347
  "\n",
 
349
  " actions, matched_plan_shape = parse_sprint_actions(completion, total_steps)\n",
350
  " except Exception:\n",
351
  " return {\n",
352
+ " \"reward\": -100.0,\n",
353
  " \"valid_json\": False,\n",
354
  " \"matched_plan_shape\": False,\n",
355
  " \"cumulative_revenue\": 0.0,\n",
 
358
  "\n",
359
  " cumulative_revenue = 0.0\n",
360
  " messages = []\n",
361
+ " reward = 10.0 if matched_plan_shape else 0.0\n",
362
+ " crisis_resolved = False\n",
363
  "\n",
364
  " for sprint_idx in range(1, total_steps + 1):\n",
365
  " if sprint_idx >= 2 and pending_crisis_items:\n",
 
374
  " sprint_idx,\n",
375
  " )\n",
376
  " cumulative_revenue += sprint_revenue\n",
 
377
  " messages.append(message)\n",
378
  "\n",
379
+ " if message.startswith(\"Overallocation\"):\n",
380
+ " reward -= 70.0\n",
381
+ " continue\n",
382
+ " if message.startswith(\"Unknown work item\"):\n",
383
+ " reward -= 60.0\n",
384
+ " continue\n",
385
+ "\n",
386
+ " reward += min(35.0, sprint_revenue / 100_000.0)\n",
387
+ " reward += sum(completed_item_points(item) for item in completed_items)\n",
388
+ " crisis_resolved = crisis_resolved or any(item.crisis for item in completed_items)\n",
389
  "\n",
390
+ " for item in active_work_queue:\n",
391
+ " if item.workType.value != \"bug\":\n",
392
+ " continue\n",
393
+ " if int(item.severity) == 5:\n",
394
+ " reward -= 18.0\n",
395
+ " elif int(item.severity) == 4:\n",
396
+ " reward -= 10.0\n",
397
+ " reward -= sum(max(0.0, game.churnMult - 1.0) * 40.0 for game in games)\n",
398
+ "\n",
399
+ " if not any(item.workType.value == \"bug\" and int(item.severity) >= 4 for item in active_work_queue):\n",
400
+ " reward += 15.0\n",
401
+ " if any(item.crisis for item in work_queue):\n",
402
+ " reward += 20.0 if crisis_resolved else -40.0\n",
403
  "\n",
404
  " return {\n",
405
+ " \"reward\": float(clamp_reward(reward)),\n",
406
  " \"valid_json\": True,\n",
407
  " \"matched_plan_shape\": matched_plan_shape,\n",
408
  " \"cumulative_revenue\": cumulative_revenue,\n",