RohitChandramouli6618 commited on
Commit
74f461a
·
1 Parent(s): 65d4590

Fix 8 issues spotted in code review: Dockerfile path, task descriptions, duplicate function, fallback score consistency, twin constants comment, has_data_lag docs

Browse files
Files changed (5) hide show
  1. README.md +4 -4
  2. baseline/evaluator.py +1 -10
  3. baseline/policy.py +19 -0
  4. inference.py +4 -11
  5. server/constants.py +4 -1
README.md CHANGED
@@ -147,11 +147,11 @@ new_infection = current + (spread_rate − natural_recovery − intervention) +
147
  | --- | --- | --- | --- | --- | --- |
148
  | **easy** | 2 | 10 | 10 | None | Single outbreak; D1 starts infected, D0 is clean |
149
  | **medium** | 4 | 15 | 8 | None | Two simultaneous outbreaks; forced triage between competing threats |
150
- | **hard** | 6 | 15 | 7 | **3 days** | Six growing outbreaks; invisible acceleration; scarce resources |
151
 
152
  **Easy** — D1 starts at 0.50 infection, D0 is clean. The agent must observe and target the correct district. A fixed-target agent ignoring observations scores ~43% and breaches hospitals 60% of the time.
153
 
154
- **Medium** — D0 and D2 start in the danger zone; D1 and D3 grow into crisis within 4–6 steps. With 8 resources across 4 districts over 15 steps, genuine triage is required.
155
 
156
  **Hard** — 3-day information lag means the agent sees infection rates from 3 days ago. The `growth_rate_hint` provides a noisy signal to estimate current state. Structural uncertainty — not testable around.
157
 
@@ -179,7 +179,7 @@ Fully deterministic — no randomness, no LLM calls. Identical trajectories alwa
179
  | --- | --- | --- |
180
  | **Hospital score** | 45% | Average capacity preserved; ×0.6 multiplier if any district collapsed |
181
  | **Containment score** | 30% | Fraction of district-days below infection threshold (first 2 steps excluded) |
182
- | **Efficiency score** | 15% | Fraction of resource actions targeting highest-infected district (uses pre-action state) |
183
  | **Speed score** | 10% | `1 − (steps / max_steps)` if episode ends early; else 0 |
184
 
185
  Hospital is weighted highest because system capacity preservation is the primary operational constraint in real outbreak response — a functioning healthcare system is the prerequisite for everything else.
@@ -309,7 +309,7 @@ python baseline/run.py
309
  ### Docker
310
 
311
  ```bash
312
- docker build -f server/Dockerfile -t cascade-containment .
313
  docker run -p 7860:7860 cascade-containment
314
  ```
315
 
 
147
  | --- | --- | --- | --- | --- | --- |
148
  | **easy** | 2 | 10 | 10 | None | Single outbreak; D1 starts infected, D0 is clean |
149
  | **medium** | 4 | 15 | 8 | None | Two simultaneous outbreaks; forced triage between competing threats |
150
+ | **hard** | 6 | 15 | 7 | **3 days** | Six seeded infections (only D2 and D4 above safe threshold); 3-day data lag; scarce resources |
151
 
152
  **Easy** — D1 starts at 0.50 infection, D0 is clean. The agent must observe and target the correct district. A fixed-target agent ignoring observations scores ~43% and breaches hospitals 60% of the time.
153
 
154
+ **Medium** — D0 starts above the infection threshold (0.42); D2 is in the warning zone (0.38, below the 0.40 threshold). D1 and D3 start low but grow into crisis within 4–6 steps via spillover. With 8 resources across 4 districts over 15 steps, genuine triage is required.
155
 
156
  **Hard** — 3-day information lag means the agent sees infection rates from 3 days ago. The `growth_rate_hint` provides a noisy signal to estimate current state. Structural uncertainty — not testable around.
157
 
 
179
  | --- | --- | --- |
180
  | **Hospital score** | 45% | Average capacity preserved; ×0.6 multiplier if any district collapsed |
181
  | **Containment score** | 30% | Fraction of district-days below infection threshold (first 2 steps excluded) |
182
+ | **Efficiency score** | 15% | Fraction of resource actions targeting highest-infected district (grader uses pre-action state to avoid penalising successful treatments) |
183
  | **Speed score** | 10% | `1 − (steps / max_steps)` if episode ends early; else 0 |
184
 
185
  Hospital is weighted highest because system capacity preservation is the primary operational constraint in real outbreak response — a functioning healthcare system is the prerequisite for everything else.
 
309
  ### Docker
310
 
311
  ```bash
312
+ docker build -t cascade-containment .
313
  docker run -p 7860:7860 cascade-containment
314
  ```
315
 
baseline/evaluator.py CHANGED
@@ -5,7 +5,7 @@ from openai import OpenAI
5
 
6
  from client import CascadeContainmentEnv
7
  from models import ContainmentAction, CityObservation
8
- from baseline.policy import get_client, build_prompt, call_llm, parse_action
9
  from core.trajectory import EpisodicMemory
10
  from core.reward import normalise_score
11
  from core.policy_update import compute_advantage, update_memory
@@ -18,15 +18,6 @@ N_ROLLOUTS = {
18
  }
19
 
20
 
21
- def build_prompt_with_memory(obs: CityObservation, memory: EpisodicMemory) -> str:
22
- base = build_prompt(obs)
23
- memory_block = memory.retrieve(obs)
24
- if not memory_block:
25
- return base
26
- injection = "\n" + memory_block + "\nApply these lessons to your current decision.\n"
27
- return base.replace("Your response:", injection + "Your response:")
28
-
29
-
30
  def run_rollout(
31
  env: Any, task_name: str, client: OpenAI,
32
  memory: EpisodicMemory, verbose: bool = True,
 
5
 
6
  from client import CascadeContainmentEnv
7
  from models import ContainmentAction, CityObservation
8
+ from baseline.policy import get_client, build_prompt, call_llm, parse_action, build_prompt_with_memory
9
  from core.trajectory import EpisodicMemory
10
  from core.reward import normalise_score
11
  from core.policy_update import compute_advantage, update_memory
 
18
  }
19
 
20
 
 
 
 
 
 
 
 
 
 
21
  def run_rollout(
22
  env: Any, task_name: str, client: OpenAI,
23
  memory: EpisodicMemory, verbose: bool = True,
baseline/policy.py CHANGED
@@ -13,6 +13,11 @@ def get_client() -> OpenAI:
13
 
14
  def build_prompt(obs: CityObservation) -> str:
15
  num_districts = len(obs.districts)
 
 
 
 
 
16
  has_data_lag = num_districts == 6
17
 
18
  sorted_districts = sorted(
@@ -169,3 +174,17 @@ def get_action(obs: CityObservation, client: OpenAI) -> ContainmentAction:
169
  prompt = build_prompt(obs)
170
  response = call_llm(prompt, client)
171
  return parse_action(response, len(obs.districts))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  def build_prompt(obs: CityObservation) -> str:
15
  num_districts = len(obs.districts)
16
+ # Infers data lag from district count because CityObservation does not expose
17
+ # data_lag_days directly. This works because hard (6 districts) is currently the
18
+ # only task with a data lag. If a new task is added with 6 districts and no lag,
19
+ # or a lag task with fewer districts, this will silently misbehave.
20
+ # Fix: expose data_lag_days in CityObservation and read it directly.
21
  has_data_lag = num_districts == 6
22
 
23
  sorted_districts = sorted(
 
174
  prompt = build_prompt(obs)
175
  response = call_llm(prompt, client)
176
  return parse_action(response, len(obs.districts))
177
+
178
+
179
+ def build_prompt_with_memory(obs: CityObservation, memory) -> str:
180
+ """
181
+ Builds the LLM prompt augmented with relevant past decisions from episodic memory.
182
+ Injects memory block just before the 'Your response:' line so the model sees
183
+ prior high-reward decisions as concrete examples before making its choice.
184
+ """
185
+ base = build_prompt(obs)
186
+ memory_block = memory.retrieve(obs)
187
+ if not memory_block:
188
+ return base
189
+ injection = "\n" + memory_block + "\nApply these lessons to your current decision.\n"
190
+ return base.replace("Your response:", injection + "Your response:")
inference.py CHANGED
@@ -10,9 +10,10 @@ import requests as http_requests
10
 
11
  from client import CascadeContainmentEnv
12
  from models import ContainmentAction
13
- from baseline.policy import get_client, build_prompt, call_llm, parse_action
14
  from core.trajectory import EpisodicMemory
15
  from core.policy_update import compute_advantage, update_memory
 
16
 
17
  API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
18
  MODEL_NAME = os.getenv("MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct")
@@ -48,15 +49,6 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> No
48
  )
49
 
50
 
51
- def build_prompt_with_memory(obs, memory: EpisodicMemory) -> str:
52
- base = build_prompt(obs)
53
- memory_block = memory.retrieve(obs)
54
- if not memory_block:
55
- return base
56
- injection = "\n" + memory_block + "\nApply these lessons to your current decision.\n"
57
- return base.replace("Your response:", injection + "Your response:")
58
-
59
-
60
  def run_rollout(
61
  env,
62
  task_name: str,
@@ -108,7 +100,8 @@ def run_rollout(
108
  if grade_resp.status_code == 200:
109
  score = grade_resp.json().get("final_score", 0.0)
110
  except Exception:
111
- score = max(0.0, min(1.0, (total_reward + 5) / 15))
 
112
 
113
  success = score >= 0.40
114
 
 
10
 
11
  from client import CascadeContainmentEnv
12
  from models import ContainmentAction
13
+ from baseline.policy import get_client, build_prompt, call_llm, parse_action, build_prompt_with_memory
14
  from core.trajectory import EpisodicMemory
15
  from core.policy_update import compute_advantage, update_memory
16
+ from core.reward import normalise_score
17
 
18
  API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
19
  MODEL_NAME = os.getenv("MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct")
 
49
  )
50
 
51
 
 
 
 
 
 
 
 
 
 
52
  def run_rollout(
53
  env,
54
  task_name: str,
 
100
  if grade_resp.status_code == 200:
101
  score = grade_resp.json().get("final_score", 0.0)
102
  except Exception:
103
+ num_districts = {"easy": 2, "medium": 4, "hard": 6}.get(task_name, 2)
104
+ score = normalise_score(total_reward, step, num_districts)
105
 
106
  success = score >= 0.40
107
 
server/constants.py CHANGED
@@ -8,7 +8,10 @@ TASK_CONFIG = {
8
  }
9
 
10
  INFECTION_THRESHOLD = 0.40 # above this → district is in the danger zone
11
- SAFE_THRESHOLD = 0.20 # below this → district is considered contained
 
 
 
12
  LOW_THRESHOLD = 0.20 # restricting below this threshold earns a penalty
13
  # real ICU overflow and triage failure kick in well before zero capacity
14
  HOSPITAL_BREACH_POINT = 0.10
 
8
  }
9
 
10
  INFECTION_THRESHOLD = 0.40 # above this → district is in the danger zone
11
+ SAFE_THRESHOLD = 0.20 # below this → district is considered contained (grader + terminal check)
12
+ # LOW_THRESHOLD and SAFE_THRESHOLD are intentionally separate even though both equal 0.20.
13
+ # SAFE_THRESHOLD is a containment concept; LOW_THRESHOLD is a restriction-penalty concept.
14
+ # Keeping them separate means they can diverge independently if the design changes.
15
  LOW_THRESHOLD = 0.20 # restricting below this threshold earns a penalty
16
  # real ICU overflow and triage failure kick in well before zero capacity
17
  HOSPITAL_BREACH_POINT = 0.10