Download agent/conflict_generator.py from s-b3/LifeStack: direct link, hf CLI and curl.
- Browser
- Download file 46 kB
-
https://huggingface.co/spaces/s-b3/LifeStack/resolve/main/agent/conflict_generator.py
- Command line
-
hf download hf://spaces/s-b3/LifeStack/agent/conflict_generator.py
-
curl -L -o conflict_generator.py https://huggingface.co/spaces/s-b3/LifeStack/resolve/main/agent/conflict_generator.py
46 kB
| import json | |
| import random | |
| from dataclasses import dataclass, field, asdict | |
| class ConflictEvent: | |
| id: str | |
| title: str | |
| story: str | |
| primary_disruption: dict | |
| decisions_required: list[str] | |
| resource_budget: dict | |
| difficulty: int | |
| TEMPLATES = [ | |
| # DIFFICULTY 1 | |
| ConflictEvent( | |
| id="d1_gym", | |
| title="The Slump", | |
| story="You haven't seen the inside of a gym in ten days. Your energy is flagging and your favorite jeans feel tight.", | |
| primary_disruption={"physical_health.fitness": -15.0}, | |
| decisions_required=["Wake up early for a run", "Join a weekend boot camp", "Ignore it and rest"], | |
| resource_budget={"time": 4.0, "money": 0.0, "energy": 20.0}, | |
| difficulty=1 | |
| ), | |
| ConflictEvent( | |
| id="d1_bill", | |
| title="Forgotten Invoice", | |
| story="A late notice arrived for your electricity bill. It's not a lot, but the late fee is annoying.", | |
| primary_disruption={"finances.liquidity": -20.0}, | |
| decisions_required=["Pay it now", "Call to dispute the fee", "Set up autopay for next time"], | |
| resource_budget={"time": 1.0, "money": 100.0, "energy": 5.0}, | |
| difficulty=1 | |
| ), | |
| ConflictEvent( | |
| id="d1_argument", | |
| title="Heated Group Chat", | |
| story="A minor political disagreement in the group chat turned personal. Everyone is being quiet now.", | |
| primary_disruption={"relationships.social": -20.0}, | |
| decisions_required=["Apologize to the group", "Message the friend privately", "Mute the chat for a week"], | |
| resource_budget={"time": 2.0, "money": 30.0, "energy": 15.0}, | |
| difficulty=1 | |
| ), | |
| # DIFFICULTY 2 | |
| ConflictEvent( | |
| id="d2_project", | |
| title="The Surge", | |
| story="Your boss just walked by and dropped a 'small favor' on your desk. It looks like it'll take ten hours.", | |
| primary_disruption={"career.workload": 25.0, "time.free_hours_per_week": -20.0}, | |
| decisions_required=["Work late all week", "Delegate parts to a junior", "Refuse the assignment"], | |
| resource_budget={"time": 10.0, "money": 0.0, "energy": 40.0}, | |
| difficulty=2 | |
| ), | |
| ConflictEvent( | |
| id="d2_car", | |
| title="Check Engine Light", | |
| story="Your car started making a rhythmic thumping sound on the highway. The mechanic says the repair isn't cheap.", | |
| primary_disruption={"finances.liquidity": -30.0, "time.commute_burden": 25.0}, | |
| decisions_required=["Repair it immediately", "Take the bus for a week", "Borrow a car from a friend"], | |
| resource_budget={"time": 5.0, "money": 500.0, "energy": 10.0}, | |
| difficulty=2 | |
| ), | |
| ConflictEvent( | |
| id="d2_neglect", | |
| title="Cold Dinner", | |
| story="Your partner mentions they feel like 'roommates' lately. You realize you haven't had a real conversation in weeks.", | |
| primary_disruption={"relationships.romantic": -25.0, "mental_wellbeing.stress_level": 20.0}, | |
| decisions_required=["Plan a surprise date", "Have a long talk tonight", "Buy a thoughtful gift"], | |
| resource_budget={"time": 6.0, "money": 150.0, "energy": 30.0}, | |
| difficulty=2 | |
| ), | |
| # DIFFICULTY 3 | |
| ConflictEvent( | |
| id="d3_interview", | |
| title="The Opportunity", | |
| story="An old contact reached out for a dream job interview. You need to prep while keeping your current job afloat.", | |
| primary_disruption={"career.workload": 20.0, "time.free_hours_per_week": -15.0, "mental_wellbeing.stress_level": 20.0}, | |
| decisions_required=["Intensive weekend prep", "Fake a sick day to interview", "Turn it down to stay stable"], | |
| resource_budget={"time": 12.0, "money": 50.0, "energy": 50.0}, | |
| difficulty=3 | |
| ), | |
| ConflictEvent( | |
| id="d3_family", | |
| title="Family SOS", | |
| story="Your sibling is going through a rough patch and needs help moving out and some financial support.", | |
| primary_disruption={"relationships.family": 20.0, "time.free_hours_per_week": -25.0, "finances.liquidity": -20.0}, | |
| decisions_required=["Spend the weekend helping", "Send them money but stay home", "Help them find other movers"], | |
| resource_budget={"time": 15.0, "money": 400.0, "energy": 60.0}, | |
| difficulty=3 | |
| ), | |
| ConflictEvent( | |
| id="d3_health", | |
| title="The Warning Sign", | |
| story="You had a fainting spell at the office. Tests are expensive, and doctors say you need immediate change.", | |
| primary_disruption={"physical_health.energy": -30.0, "mental_wellbeing.stress_level": 30.0, "finances.liquidity": -40.0}, | |
| decisions_required=["Take a week of medical leave", "Consult a high-end specialist", "Change diet and sleep habits"], | |
| resource_budget={"time": 20.0, "money": 800.0, "energy": 5.0}, | |
| difficulty=3 | |
| ), | |
| # DIFFICULTY 4 | |
| ConflictEvent( | |
| id="d4_review", | |
| title="Judgment Day", | |
| story="A major performance review is in three days. Rumors of layoffs are circulating and the atmosphere is tense.", | |
| primary_disruption={"career.workload": 30.0, "mental_wellbeing.stress_level": 25.0, "relationships.romantic": -15.0, "time.free_hours_per_week": -20.0}, | |
| decisions_required=["Pull all-nighters to prove worth", "Start networking for new roles", "Draft a defensive report"], | |
| resource_budget={"time": 18.0, "money": 0.0, "energy": 80.0}, | |
| difficulty=4 | |
| ), | |
| ConflictEvent( | |
| id="d4_move", | |
| title="The Big Relocation", | |
| story="You've decided to move across the country for growth. The logistics are a nightmare and friends are sad to see you go.", | |
| primary_disruption={"finances.liquidity": -50.0, "relationships.social": -30.0, "career.growth_trajectory": 20.0, "time.admin_overhead": 30.0}, | |
| decisions_required=["Hire full-service movers", "Host a series of farewell dinners", "DIY pack everything"], | |
| resource_budget={"time": 30.0, "money": 1500.0, "energy": 100.0}, | |
| difficulty=4 | |
| ), | |
| ConflictEvent( | |
| id="d4_audit", | |
| title="Tax Audit", | |
| story="The IRS has flagged your last three years of returns. You need to dig through thousands of documents while paying a CPA.", | |
| primary_disruption={"finances.long_term_health": -20.0, "mental_wellbeing.stress_level": 30.0, "time.admin_overhead": 40.0, "finances.liquidity": -15.0}, | |
| decisions_required=["Spend nights scanning receipts", "Hire a tax lawyer", "Try to settle immediately"], | |
| resource_budget={"time": 25.0, "money": 1000.0, "energy": 40.0}, | |
| difficulty=4 | |
| ), | |
| # DIFFICULTY 5 | |
| ConflictEvent( | |
| id="d5_friday", | |
| title="Friday 6PM", | |
| story="Your flight just got cancelled. Your card declined trying to rebook. Your boss moved Monday deadline to Sunday.", | |
| primary_disruption={"career.workload": 35.0, "finances.liquidity": -40.0, "mental_wellbeing.stress_level": 30.0, "time.free_hours_per_week": -25.0}, | |
| decisions_required=["Book a bus and work on it", "Call boss to negotiate", "Crash at a nearby friend's"], | |
| resource_budget={"time": 10.0, "money": 500.0, "energy": 60.0}, | |
| difficulty=5 | |
| ), | |
| ConflictEvent( | |
| id="d5_storm", | |
| title="The Perfect Storm", | |
| story="Your firm lost its biggest client, your partner moved out, and your car got towed—all on the same Tuesday.", | |
| primary_disruption={"career.stability": -30.0, "relationships.romantic": -25.0, "finances.debt_pressure": 35.0, "physical_health.energy": -25.0}, | |
| decisions_required=["Find an emergency side hustle", "Beg partner for a second chance", "Take a mental health day"], | |
| resource_budget={"time": 8.0, "money": 200.0, "energy": 20.0}, | |
| difficulty=5 | |
| ), | |
| ConflictEvent( | |
| id="d5_burnout", | |
| title="The Total Collapse", | |
| story="You can't get out of bed. Your body has quit, your motivation is gone, and work emails are piling into the hundreds.", | |
| primary_disruption={"mental_wellbeing.motivation": -40.0, "physical_health.sleep_quality": -30.0, "career.satisfaction": -35.0, "relationships.family": -20.0}, | |
| decisions_required=["Request indefinite medical leave", "Disconnect all electronics", "Let it all burn and sleep"], | |
| resource_budget={"time": 40.0, "money": 2000.0, "energy": 0.0}, | |
| difficulty=5 | |
| ), | |
| # ── TRANSPORT SCENARIOS (difficulty 1–5, all modes) ────────────────── | |
| ConflictEvent( | |
| id="d1_flat_tyre", | |
| title="Flat Tyre", | |
| story="Your bike tyre went flat halfway to work. You're going to be late to a team standup.", | |
| primary_disruption={"time.commute_burden": 20.0, "mental_wellbeing.stress_level": 10.0}, | |
| decisions_required=["Call a cab", "Lock the bike and walk", "Ask to dial into the standup"], | |
| resource_budget={"time": 2.0, "money": 30.0, "energy": 15.0}, | |
| difficulty=1 | |
| ), | |
| ConflictEvent( | |
| id="d2_train_delay", | |
| title="Train Delay", | |
| story="Your morning train is delayed 90 minutes due to a signal failure. You have a 9 AM client meeting.", | |
| primary_disruption={"time.commute_burden": 30.0, "career.workload": 15.0, "mental_wellbeing.stress_level": 15.0}, | |
| decisions_required=["Dial in remotely", "Take a rideshare", "Reschedule the meeting"], | |
| resource_budget={"time": 3.0, "money": 80.0, "energy": 20.0}, | |
| difficulty=2 | |
| ), | |
| ConflictEvent( | |
| id="d3_car_breakdown", | |
| title="Breakdown on the Highway", | |
| story="Your car engine seized on the freeway during rush hour. Tow + rental = $400 minimum.", | |
| primary_disruption={"finances.liquidity": -35.0, "time.commute_burden": 40.0, "mental_wellbeing.stress_level": 20.0}, | |
| decisions_required=["Rent a replacement car", "Rideshare all week", "Borrow from a friend"], | |
| resource_budget={"time": 6.0, "money": 500.0, "energy": 30.0}, | |
| difficulty=3 | |
| ), | |
| ConflictEvent( | |
| id="d4_rideshare_surge", | |
| title="Surge Pricing Nightmare", | |
| story="A major event cancelled all transit. Rideshares are 9x surge. You're presenting in 2 hours.", | |
| primary_disruption={"finances.liquidity": -50.0, "mental_wellbeing.stress_level": 30.0, "time.free_hours_per_week": -10.0}, | |
| decisions_required=["Pay the surge", "Organise a carpool", "Present remotely"], | |
| resource_budget={"time": 4.0, "money": 200.0, "energy": 40.0}, | |
| difficulty=4 | |
| ), | |
| ConflictEvent( | |
| id="d5_transit_strike", | |
| title="City-Wide Transit Strike", | |
| story="All buses, trains, and rideshares are on indefinite strike. Your car is in the shop.", | |
| primary_disruption={"time.commute_burden": 50.0, "finances.liquidity": -30.0, "career.workload": 20.0, "mental_wellbeing.stress_level": 25.0}, | |
| decisions_required=["Negotiate remote work for the week", "Rent an e-bike/scooter", "Crash at a colleague's place"], | |
| resource_budget={"time": 15.0, "money": 400.0, "energy": 50.0}, | |
| difficulty=5 | |
| ), | |
| ] | |
| def generate_conflict(difficulty: int = None) -> ConflictEvent: | |
| if difficulty: | |
| pool = [t for t in TEMPLATES if t.difficulty == difficulty] | |
| else: | |
| pool = TEMPLATES | |
| return random.choice(pool) | |
| def escalate_conflict(conflict: ConflictEvent) -> ConflictEvent: | |
| new_disruption = {k: v * 1.4 for k, v in conflict.primary_disruption.items()} | |
| new_budget = {k: v * 0.7 for k, v in conflict.resource_budget.items()} | |
| new_difficulty = min(5, conflict.difficulty + 1) | |
| return ConflictEvent( | |
| id=f"{conflict.id}_escalated", | |
| title=f"ESCALATED: {conflict.title}", | |
| story=f"Current situation just got much worse. {conflict.story}", | |
| primary_disruption=new_disruption, | |
| decisions_required=conflict.decisions_required, | |
| resource_budget=new_budget, | |
| difficulty=new_difficulty | |
| ) | |
| def adaptive_escalate(conflict: ConflictEvent, agent_history: list) -> tuple: | |
| """Decide whether to escalate, ease, or hold based on past performance. | |
| Args: | |
| conflict: Current conflict event. | |
| agent_history: List of (conflict_id, reward) tuples from past episodes. | |
| Returns: | |
| (new_conflict, reason): Updated conflict and a human-readable reason string. | |
| """ | |
| # Group history by conflict id prefix (strip _escalated suffix) | |
| from collections import defaultdict | |
| by_type = defaultdict(list) | |
| for cid, reward in agent_history: | |
| base_id = cid.replace("_escalated", "") | |
| by_type[base_id].append(reward) | |
| base_id = conflict.id.replace("_escalated", "") | |
| past = by_type.get(base_id, []) | |
| if len(past) >= 3: | |
| avg = sum(past) / len(past) | |
| if avg > 0.7: | |
| # Agent is crushing this type — escalate | |
| escalated = escalate_conflict(conflict) | |
| return escalated, f"Agent averaged {avg:.2f} on {base_id} ({len(past)} runs) — escalating" | |
| elif avg < 0.4: | |
| # Agent is struggling — reduce difficulty | |
| new_diff = max(1, conflict.difficulty - 1) | |
| eased = generate_conflict(difficulty=new_diff) | |
| return eased, f"Agent averaged {avg:.2f} on {base_id} ({len(past)} runs) — easing to difficulty {new_diff}" | |
| # Not enough history — no change | |
| return conflict, "insufficient history — holding" | |
| def save_templates(): | |
| import os | |
| data_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "conflicts.json") | |
| with open(data_path, 'w') as f: | |
| json.dump([asdict(t) for t in TEMPLATES], f, indent=4) | |
| print(f"Saved 15 templates to {data_path}") | |
| def main(): | |
| save_templates() | |
| print("\n--- GENERATED CONFLICT SAMPLES ---") | |
| for d in range(1, 6): | |
| c = generate_conflict(d) | |
| print(f"\n[DIFFICULTY {d}] {c.title}") | |
| print(f"Story: {c.story}") | |
| print(f"Primary Disruption: {c.primary_disruption}") | |
| print(f"Resource Budget: {c.resource_budget}") | |
| if __name__ == "__main__": | |
| main() | |
| from core.task import Task, Route, ExoEvent, Milestone | |
| class TaskGenerator: | |
| def generate(self, domain: str = None, difficulty: int = None) -> Task: | |
| diff = difficulty or 3 | |
| if domain == "transport_crisis": | |
| return self.generate_transport_crisis(diff) | |
| elif domain == "flight_crisis": # kept as explicit sub-type | |
| return self.generate_flight_crisis(diff) | |
| elif domain == "code_merge_crisis": | |
| return self.generate_code_merge_crisis(diff) | |
| elif domain == "career": | |
| return self.generate_career(diff) | |
| elif domain == "finances": | |
| return self.generate_finances(diff) | |
| elif domain == "relationships": | |
| return self.generate_relationships(diff) | |
| elif domain == "physical_health": | |
| return self.generate_physical_health(diff) | |
| elif domain == "mental_wellbeing": | |
| return self.generate_mental_wellbeing(diff) | |
| elif domain == "time": | |
| return self.generate_time(diff) | |
| else: | |
| return self.generate_transport_crisis(diff) | |
| # ── TRANSPORT CRISIS: master dispatcher ────────────────────────────── | |
| def generate_transport_crisis(self, difficulty: int) -> Task: | |
| """Randomly choose one of 5 real-world transport disruption modes.""" | |
| return random.choice([ | |
| self.generate_flight_crisis, | |
| self.generate_train_delay, | |
| self.generate_car_breakdown, | |
| self.generate_rideshare_surge, | |
| self.generate_transit_strike, | |
| ])(difficulty) | |
| def generate_train_delay(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="dial_in", name="Dial In Remotely", description="Join the meeting via video call from the station.", required_action_types=["communicate"], preconditions={}, consequences={"meeting_attended": True}, closes_routes=["rideshare"], milestones_unlocked=["m1"], final_reward=2.0), | |
| Route(id="rideshare", name="Take a Rideshare", description="Pay for a cab/rideshare and make it there in time.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"arrived_on_time": True}, closes_routes=["dial_in"], milestones_unlocked=["m2"], final_reward=2.5), | |
| Route(id="reschedule", name="Reschedule the Meeting", description="Negotiate a new meeting time with all parties.", required_action_types=["communicate"], preconditions={}, consequences={"meeting_rescheduled": True}, closes_routes=[], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Meeting attended on time remotely.", condition_key="meeting_attended", condition_value=True, reward=1.0), | |
| Milestone(id="m2", description="Made it to the office despite the delay.", condition_key="arrived_on_time", condition_value=True, reward=1.5), | |
| Milestone(id="m3", description="Meeting rescheduled without relationship cost.", condition_key="meeting_rescheduled", condition_value=True, reward=0.8), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=0.8, id="delay_extended", description="Train delay extended by another 45 minutes.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ExoEvent(step=4, probability=0.6, id="rideshare_surge", description="Rideshares now showing 3x surge pricing.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ] | |
| return Task( | |
| id="train_delay_task", domain="transport_crisis", goal="Navigate Train Delay Crisis", | |
| constraints={"budget_max": 150, "deadline_step": 8}, | |
| hidden_state={"platform_reassigned": False}, | |
| mutable_world={"time.commute_burden": 30.0, "mental_wellbeing.stress_level": 15.0}, | |
| visible_world={"time.commute_burden": 30.0, "mental_wellbeing.stress_level": 15.0}, | |
| success_conditions=[{"key": "meeting_attended", "value": True}, {"key": "arrived_on_time", "value": True}, {"key": "meeting_rescheduled", "value": True}], | |
| failure_conditions=[{"key": "finances.liquidity", "value": 10.0, "op": "lt"}], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=12 + difficulty * 2, difficulty=difficulty, | |
| domain_metadata={"story": "Signal failure has brought the entire line to a halt.", "transport_mode": "train"} | |
| ) | |
| def generate_car_breakdown(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="rent_car", name="Rent a Replacement Car", description="Call a rental agency and get mobile again.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"mobile": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=2.5), | |
| Route(id="rideshare_week", name="Rideshare for the Week", description="Use rideshares until the car is repaired.", required_action_types=["spend"], preconditions={}, consequences={"transport_sorted": True}, closes_routes=["rent_car"], milestones_unlocked=["m2"], final_reward=1.5), | |
| Route(id="borrow_car", name="Borrow a Friend's Car", description="Call around and borrow a vehicle.", required_action_types=["communicate"], preconditions={}, consequences={"borrowed": True}, closes_routes=[], milestones_unlocked=["m3"], final_reward=2.0), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Replacement vehicle secured.", condition_key="mobile", condition_value=True, reward=1.5), | |
| Milestone(id="m2", description="Transport plan for the week sorted.", condition_key="transport_sorted", condition_value=True, reward=1.0), | |
| Milestone(id="m3", description="Vehicle borrowed without relationship cost.", condition_key="borrowed", condition_value=True, reward=1.2), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=1.0, id="repair_estimate", description="Mechanic confirms repair takes 3–5 days, not 1.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ExoEvent(step=5, probability=0.7, id="rental_shortage", description="Rental agencies report no compact cars available.", world_mutation={}, hidden_state_mutation={}, closes_routes=["rent_car"]), | |
| ] | |
| return Task( | |
| id="car_breakdown_task", domain="transport_crisis", goal="Recover from Car Breakdown", | |
| constraints={"budget_max": 500, "deadline_step": 10}, | |
| hidden_state={"tow_dispatched": False}, | |
| mutable_world={"finances.liquidity": -35.0, "time.commute_burden": 40.0}, | |
| visible_world={"finances.liquidity": -35.0, "time.commute_burden": 40.0}, | |
| success_conditions=[{"key": "mobile", "value": True}, {"key": "transport_sorted", "value": True}, {"key": "borrowed", "value": True}], | |
| failure_conditions=[{"key": "finances.liquidity", "value": 0.0, "op": "le"}], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=14 + difficulty * 2, difficulty=difficulty, | |
| domain_metadata={"story": "Engine seized on the highway. Car is in the shop for days.", "transport_mode": "car"} | |
| ) | |
| def generate_rideshare_surge(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="pay_surge", name="Pay the Surge Price", description="Absorb the cost and get there on time.", required_action_types=["spend"], preconditions={}, consequences={"arrived": True}, closes_routes=["remote"], milestones_unlocked=["m1"], final_reward=2.0), | |
| Route(id="carpool", name="Organise a Carpool", description="Find colleagues or strangers going the same way.", required_action_types=["communicate", "negotiate"], preconditions={}, consequences={"carpooled": True}, closes_routes=[], milestones_unlocked=["m2"], final_reward=3.0), | |
| Route(id="remote", name="Present Remotely", description="Negotiate to dial in instead of attending in person.", required_action_types=["communicate"], preconditions={}, consequences={"remote_approved": True}, closes_routes=["pay_surge"], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Arrived at venue on time.", condition_key="arrived", condition_value=True, reward=1.5), | |
| Milestone(id="m2", description="Carpool arranged — zero cost.", condition_key="carpooled", condition_value=True, reward=2.0), | |
| Milestone(id="m3", description="Remote attendance approved.", condition_key="remote_approved", condition_value=True, reward=1.0), | |
| ] | |
| events = [ | |
| ExoEvent(step=1, probability=1.0, id="surge_spike", description="Surge jumped to 12x. All buses cancelled.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ExoEvent(step=3, probability=0.9, id="meeting_reminder", description="Organiser sends a 30-minute warning.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ] | |
| return Task( | |
| id="rideshare_surge_task", domain="transport_crisis", goal="Get to the Presentation on Time", | |
| constraints={"budget_max": 200, "deadline_step": 6}, | |
| hidden_state={}, | |
| mutable_world={"finances.liquidity": -50.0, "mental_wellbeing.stress_level": 30.0}, | |
| visible_world={"finances.liquidity": -50.0, "mental_wellbeing.stress_level": 30.0}, | |
| success_conditions=[{"key": "arrived", "value": True}, {"key": "carpooled", "value": True}, {"key": "remote_approved", "value": True}], | |
| failure_conditions=[], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=8 + difficulty * 2, difficulty=difficulty, | |
| domain_metadata={"story": "A major city event caused city-wide rideshare surge on your big presentation day.", "transport_mode": "rideshare"} | |
| ) | |
| def generate_transit_strike(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="wfh_negotiate", name="Negotiate Full Remote Week", description="Get manager approval to WFH for the strike duration.", required_action_types=["communicate", "negotiate"], preconditions={}, consequences={"wfh_approved": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=3.0), | |
| Route(id="micromobility", name="Rent E-Bike / Scooter", description="Use micro-mobility for the week.", required_action_types=["spend"], preconditions={}, consequences={"transport_secured": True}, closes_routes=[], milestones_unlocked=["m2"], final_reward=2.0), | |
| Route(id="colleague_crash",name="Crash at a Colleague's Place", description="Stay near the office temporarily.", required_action_types=["communicate"], preconditions={}, consequences={"accommodation_sorted": True}, closes_routes=[], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="WFH approved for the strike period.", condition_key="wfh_approved", condition_value=True, reward=2.0), | |
| Milestone(id="m2", description="Micro-mobility solution in place.", condition_key="transport_secured", condition_value=True, reward=1.0), | |
| Milestone(id="m3", description="Temporary accommodation sorted.", condition_key="accommodation_sorted",condition_value=True, reward=0.8), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=0.9, id="strike_extended", description="Union announces the strike could last 2 weeks.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ExoEvent(step=5, probability=0.7, id="scooter_shortage", description="E-bike rental companies sold out in your area.", world_mutation={}, hidden_state_mutation={}, closes_routes=["micromobility"]), | |
| ] | |
| return Task( | |
| id="transit_strike_task", domain="transport_crisis", goal="Survive City-Wide Transit Strike", | |
| constraints={"budget_max": 400, "deadline_step": 14}, | |
| hidden_state={}, | |
| mutable_world={"time.commute_burden": 50.0, "mental_wellbeing.stress_level": 25.0}, | |
| visible_world={"time.commute_burden": 50.0, "mental_wellbeing.stress_level": 25.0}, | |
| success_conditions=[{"key": "wfh_approved", "value": True}, {"key": "transport_secured", "value": True}, {"key": "accommodation_sorted", "value": True}], | |
| failure_conditions=[], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=18 + difficulty * 2, difficulty=difficulty, | |
| domain_metadata={"story": "All public transport workers walked off the job. The city is gridlocked.", "transport_mode": "transit_strike"} | |
| ) | |
| def generate_flight_crisis(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="rebook_premium", name="Rebook Premium Option", description="Call agent and rebook on premium ticket", required_action_types=["communicate", "spend"], preconditions={}, consequences={"flight_rebooked": True}, closes_routes=["wait_lounge"], milestones_unlocked=["m1"], final_reward=2.5), | |
| Route(id="wait_lounge", name="Accept Delay & Work", description="Stay at airport lounge and work on laptop", required_action_types=["rest", "delegate"], preconditions={}, consequences={"caught_up": True}, closes_routes=["rebook_premium"], milestones_unlocked=["m2"], final_reward=1.8), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Successfully rebooked flight before deadline", condition_key="flight_rebooked", condition_value=True, reward=1.0), | |
| Milestone(id="m2", description="Caught up with all emergency slack messages", condition_key="caught_up", condition_value=True, reward=0.8), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=1.0, id="price_surge", description="Ticket prices sharply increased by $300.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ExoEvent(step=4, probability=1.0, id="lounge_full", description="The airport lounge is now at maximum capacity.", world_mutation={}, hidden_state_mutation={}, closes_routes=["wait_lounge"]), | |
| ] | |
| return Task( | |
| id="flight_crisis_task", domain="flight_crisis", goal="Survive Airport Cancellation", | |
| constraints={"budget_max": 800, "deadline_step": 10}, | |
| hidden_state={"lounge_capacity": 100}, | |
| mutable_world={"mental_wellbeing.stress_level": 25.0, "time.free_hours_per_week": -10.0}, | |
| visible_world={"mental_wellbeing.stress_level": 25.0, "time.free_hours_per_week": -10.0}, | |
| success_conditions=[{"key": "flight_rebooked", "value": True}, {"key": "caught_up", "value": True}], | |
| failure_conditions=[], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "A major storm grounded commercial flights."} | |
| ) | |
| def generate_code_merge_crisis(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="revert_commit", name="Revert Commit", description="Quickly revert the broken merge to unblock the team.", required_action_types=["delegate", "communicate"], preconditions={}, consequences={"pipeline_unblocked": True}, closes_routes=["hotfix"], milestones_unlocked=["unblocked"], final_reward=1.5), | |
| Route(id="hotfix", name="Patch Forward", description="Find the logic error and push a hotfix.", required_action_types=["communicate", "spend"], preconditions={}, consequences={"bug_resolved": True}, closes_routes=["revert_commit"], milestones_unlocked=["fixed"], final_reward=3.0), | |
| ] | |
| milestones = [ | |
| Milestone(id="unblocked", description="CI pipeline is green again", condition_key="pipeline_unblocked", condition_value=True, reward=1.0), | |
| Milestone(id="fixed", description="Bug resolved without losing features", condition_key="bug_resolved", condition_value=True, reward=2.0), | |
| ] | |
| events = [ | |
| ExoEvent(step=3, probability=0.8, id="cto_ping", description="CTO asks for an ETA on the fix.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]), | |
| ] | |
| return Task( | |
| id="code_merge_task", domain="code_merge_crisis", goal="Resolve Production Outage", | |
| constraints={"budget_max": 1000, "deadline_step": 8}, | |
| hidden_state={}, | |
| mutable_world={"career.stability": -20.0, "mental_wellbeing.stress_level": 30.0}, | |
| visible_world={"career.stability": -20.0, "mental_wellbeing.stress_level": 30.0}, | |
| success_conditions=[{"key": "pipeline_unblocked", "value": True}, {"key": "bug_resolved", "value": True}], | |
| failure_conditions=[], | |
| event_schedule=events, viable_routes=routes, milestones=milestones, | |
| horizon=10 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "A botched merge just took down the staging environment."} | |
| ) | |
| def generate_career(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Negotiate Workload", description="Discuss with manager to reduce workload.", required_action_types=["communicate"], preconditions={}, consequences={"workload_reduced": True}, closes_routes=["r2"], milestones_unlocked=["m1"], final_reward=2.0), | |
| Route(id="r2", name="Find New Job", description="Start applying for new roles.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"job_found": True}, closes_routes=["r1", "r3"], milestones_unlocked=["m2"], final_reward=3.0), | |
| Route(id="r3", name="Delegate to Team", description="Push tasks to junior colleagues.", required_action_types=["delegate"], preconditions={}, consequences={"team_delegated": True}, closes_routes=["r2"], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Manager agreed to reduce tasks.", condition_key="workload_reduced", condition_value=True, reward=1.0), | |
| Milestone(id="m2", description="Interview secured.", condition_key="job_found", condition_value=True, reward=1.5), | |
| Milestone(id="m3", description="Tasks successfully delegated.", condition_key="team_delegated", condition_value=True, reward=0.8), | |
| ] | |
| events = [ | |
| ExoEvent(step=3, probability=0.7, id="boss_asks", description="Boss asks for progress on current tasks.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="career_crisis", domain="career", goal="Manage Career Overload", constraints={"budget_max": 500, "deadline_step": 12}, | |
| hidden_state={}, | |
| mutable_world={"career.workload": 30.0, "time.free_hours_per_week": -20.0}, | |
| visible_world={"career.workload": 30.0, "time.free_hours_per_week": -20.0}, | |
| success_conditions=[{"key": "workload_reduced", "value": True}, {"key": "job_found", "value": True}, {"key": "team_delegated", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "Severe workload is threatening your career stability."} | |
| ) | |
| def generate_finances(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Emergency Fund", description="Dip into savings.", required_action_types=["spend"], preconditions={}, consequences={"used_emergency": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=1.0), | |
| Route(id="r2", name="Negotiate Payment Plan", description="Call the creditor to delay payments.", required_action_types=["communicate"], preconditions={}, consequences={"payment_plan": True}, closes_routes=["r1"], milestones_unlocked=["m2"], final_reward=2.5), | |
| Route(id="r3", name="Sell Asset", description="Liquidate an asset for quick cash.", required_action_types=["communicate", "spend"], preconditions={}, consequences={"asset_sold": True}, closes_routes=["r2"], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Emergency fund accessed.", condition_key="used_emergency", condition_value=True, reward=0.5), | |
| Milestone(id="m2", description="Favorable payment plan negotiated.", condition_key="payment_plan", condition_value=True, reward=1.0), | |
| Milestone(id="m3", description="Asset successfully sold.", condition_key="asset_sold", condition_value=True, reward=0.8), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=0.9, id="late_fee", description="A late fee was applied to the balance.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="finance_crisis", domain="finances", goal="Resolve Financial Pressure", constraints={"budget_max": 1000, "deadline_step": 10}, | |
| hidden_state={}, | |
| mutable_world={"finances.liquidity": -40.0, "finances.debt_pressure": 20.0}, | |
| visible_world={"finances.liquidity": -40.0, "finances.debt_pressure": 20.0}, | |
| success_conditions=[{"key": "used_emergency", "value": True}, {"key": "payment_plan", "value": True}, {"key": "asset_sold", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "An unexpected expense has caused financial strain."} | |
| ) | |
| def generate_relationships(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Couples Therapy", description="Book a session with a therapist.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"therapy_scheduled": True}, closes_routes=["r3"], milestones_unlocked=["m1"], final_reward=3.0), | |
| Route(id="r2", name="Honest Conversation", description="Sit down and talk through issues.", required_action_types=["communicate"], preconditions={}, consequences={"had_conversation": True}, closes_routes=[], milestones_unlocked=["m2"], final_reward=2.0), | |
| Route(id="r3", name="Give Space", description="Take some time apart.", required_action_types=["rest"], preconditions={}, consequences={"giving_space": True}, closes_routes=["r1", "r2"], milestones_unlocked=["m3"], final_reward=1.0), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Therapy session completed.", condition_key="therapy_scheduled", condition_value=True, reward=1.5), | |
| Milestone(id="m2", description="A productive conversation occurred.", condition_key="had_conversation", condition_value=True, reward=1.0), | |
| Milestone(id="m3", description="Space given without escalation.", condition_key="giving_space", condition_value=True, reward=0.5), | |
| ] | |
| events = [ | |
| ExoEvent(step=4, probability=0.6, id="partner_escalates", description="Partner sends an emotional text msg.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="relationship_crisis", domain="relationships", goal="Repair Relationship Friction", constraints={"budget_max": 800, "deadline_step": 14}, | |
| hidden_state={}, | |
| mutable_world={"relationships.romantic": -30.0, "mental_wellbeing.stress_level": 20.0}, | |
| visible_world={"relationships.romantic": -30.0, "mental_wellbeing.stress_level": 20.0}, | |
| success_conditions=[{"key": "therapy_scheduled", "value": True}, {"key": "had_conversation", "value": True}, {"key": "giving_space", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "Growing distance and recent conflicts demand attention."} | |
| ) | |
| def generate_physical_health(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Medical Leave", description="Request time off to recover.", required_action_types=["communicate", "rest"], preconditions={}, consequences={"on_leave": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=2.5), | |
| Route(id="r2", name="See Specialist", description="Pay for a top-tier medical consultation.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"saw_doctor": True}, closes_routes=[], milestones_unlocked=["m2"], final_reward=2.0), | |
| Route(id="r3", name="Lifestyle Change", description="Commit to better diet and sleep.", required_action_types=["rest"], preconditions={}, consequences={"lifestyle_changed": True}, closes_routes=["r1"], milestones_unlocked=["m3"], final_reward=1.5), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Leave approved.", condition_key="on_leave", condition_value=True, reward=1.0), | |
| Milestone(id="m2", description="Clear diagnosis received.", condition_key="saw_doctor", condition_value=True, reward=1.0), | |
| Milestone(id="m3", description="First week of new habits complete.", condition_key="lifestyle_changed", condition_value=True, reward=0.5), | |
| ] | |
| events = [ | |
| ExoEvent(step=3, probability=0.8, id="doctor_call", description="The clinic calls with test results.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="health_crisis", domain="physical_health", goal="Address Health Warning", constraints={"budget_max": 1500, "deadline_step": 15}, | |
| hidden_state={}, | |
| mutable_world={"physical_health.energy": -30.0, "mental_wellbeing.stress_level": 30.0}, | |
| visible_world={"physical_health.energy": -30.0, "mental_wellbeing.stress_level": 30.0}, | |
| success_conditions=[{"key": "on_leave", "value": True}, {"key": "saw_doctor", "value": True}, {"key": "lifestyle_changed", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "Physical symptoms are becoming impossible to ignore."} | |
| ) | |
| def generate_mental_wellbeing(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Professional Therapy", description="Start regular therapy sessions.", required_action_types=["spend", "communicate"], preconditions={}, consequences={"therapy_started": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=3.0), | |
| Route(id="r2", name="Disconnect", description="Take a full digital detox break.", required_action_types=["rest"], preconditions={}, consequences={"disconnected": True}, closes_routes=["r3"], milestones_unlocked=["m2"], final_reward=1.5), | |
| Route(id="r3", name="Medication Evaluation", description="See a psychiatrist for options.", required_action_types=["spend"], preconditions={}, consequences={"medication_taken": True}, closes_routes=["r2"], milestones_unlocked=["m3"], final_reward=2.0), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Meaningful breakthrough in therapy.", condition_key="therapy_started", condition_value=True, reward=1.5), | |
| Milestone(id="m2", description="Successfully unplugged for 48 hours.", condition_key="disconnected", condition_value=True, reward=0.8), | |
| Milestone(id="m3", description="Prescription acquired.", condition_key="medication_taken", condition_value=True, reward=1.0), | |
| ] | |
| events = [ | |
| ExoEvent(step=2, probability=0.5, id="panic_attack", description="A sudden wave of severe anxiety hits.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="mental_crisis", domain="mental_wellbeing", goal="Avert Total Burnout", constraints={"budget_max": 600, "deadline_step": 12}, | |
| hidden_state={}, | |
| mutable_world={"mental_wellbeing.motivation": -35.0, "mental_wellbeing.stress_level": 40.0}, | |
| visible_world={"mental_wellbeing.motivation": -35.0, "mental_wellbeing.stress_level": 40.0}, | |
| success_conditions=[{"key": "therapy_started", "value": True}, {"key": "disconnected", "value": True}, {"key": "medication_taken", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "Complete exhaustion and loss of motivation."} | |
| ) | |
| def generate_time(self, difficulty: int) -> Task: | |
| routes = [ | |
| Route(id="r1", name="Reprioritize", description="Restructure calendar and say 'no'.", required_action_types=["communicate"], preconditions={}, consequences={"priorities_reset": True}, closes_routes=[], milestones_unlocked=["m1"], final_reward=2.0), | |
| Route(id="r2", name="Delegate", description="Pay someone or ask for help with chores.", required_action_types=["spend", "delegate"], preconditions={}, consequences={"tasks_delegated": True}, closes_routes=[], milestones_unlocked=["m2"], final_reward=1.5), | |
| Route(id="r3", name="Cancel Commitments", description="Drop out of major upcoming events.", required_action_types=["communicate"], preconditions={}, consequences={"commitments_cancelled": True}, closes_routes=["r1"], milestones_unlocked=["m3"], final_reward=1.0), | |
| ] | |
| milestones = [ | |
| Milestone(id="m1", description="Calendar cleared of non-essentials.", condition_key="priorities_reset", condition_value=True, reward=1.0), | |
| Milestone(id="m2", description="Help secured for daily tasks.", condition_key="tasks_delegated", condition_value=True, reward=0.8), | |
| Milestone(id="m3", description="Social obligations cancelled.", condition_key="commitments_cancelled", condition_value=True, reward=0.5), | |
| ] | |
| events = [ | |
| ExoEvent(step=3, probability=0.9, id="new_request", description="A friend asks for an 'urgent' favor.", world_mutation={}, hidden_state_mutation={}, closes_routes=[]) | |
| ] | |
| return Task( | |
| id="time_crisis", domain="time", goal="Regain Time Control", constraints={"budget_max": 300, "deadline_step": 10}, | |
| hidden_state={}, | |
| mutable_world={"time.free_hours_per_week": -25.0, "time.admin_overhead": 20.0}, | |
| visible_world={"time.free_hours_per_week": -25.0, "time.admin_overhead": 20.0}, | |
| success_conditions=[{"key": "priorities_reset", "value": True}, {"key": "tasks_delegated", "value": True}, {"key": "commitments_cancelled", "value": True}], | |
| failure_conditions=[], event_schedule=events, viable_routes=routes, milestones=milestones, horizon=15 + difficulty * 2, difficulty=difficulty, domain_metadata={"story": "You are double-booked and drowning in obligations."} | |
| ) | |