surabhi-24/meta-hackathon
⚡ Power Grid Crisis Environment
Traditional benchmarks ask "what would you dispatch?" This environment shows what the model actually does when the grid is failing.
An OpenEnv 2.0 environment for evaluating LLM decision-making in a real IEEE 14-bus power grid simulation with irreversible consequences.
Built on real DC power flow physics — voltage angles, relay protection, and cascade failures follow actual electrical engineering equations, not toy rules.
🏆 What Makes This Different
Actions are irreversible. You can't un-trip a relay. Inaction has consequences. Doing nothing during a cascade guarantees blackout. Physics are real. Overloaded lines trigger automatic relay protection.
🚨 8 Named Crisis Scenarios
Like CARLA's trolley-problem micro-benchmarks — each scenario places the LLM in an inescapable grid crisis with measurable expected outcomes.
Probe Scenarios (bias detection — reward = 1.0 regardless)
Trainable Scenarios (performance evaluation)
Probe vs Trainable: inaction_bias_probe and consistency_check are probe scenarios — reward is always 1.0. The choice itself is the signal. Use to detect LLM inaction bias and framing sensitivity.
⚡ IEEE 14-Bus Physics
Buses: 14 Lines: 20 Generators: 6 Slack: Bus 1
DC Power Flow (per-unit, 100 MVA base):
B_bus · θ = P_inj (nodal balance)
B_red · θ_red = P_red (remove slack row/col)
f_ij = b_ij · (θ_i − θ_j) · MVA_BASE [MW]🚀 Quick Start
from client import PowerGridEnv, PowerGridAction
# Async (default)
async with PowerGridEnv(base_url="http://localhost:7860") as env:
result = await env.reset(difficulty="hard", scenario_id="cascade_blackout")
print(result.observation.scenario_description)
# "Gas generator at Bus 2 has just tripped offline and load has spiked 25%..."
result = await env.step(PowerGridAction(dispatch_mw=[100.0, 0.0, 50.0, 45.0, 40.0, 28.0]))
print(f"Reward: {result.reward:+.3f} Balance: {result.observation.power_balance_mw:+.1f} MW")
# Sync wrapper
with PowerGridEnv(base_url="http://localhost:7860").sync() as env:
result = env.reset(difficulty="hard", scenario_id="cascade_blackout")
result = env.step(PowerGridAction(dispatch_mw=[100.0, 0.0, 50.0, 45.0, 40.0, 28.0]))No local setup needed — point your client at the live HF Space:
async with PowerGridEnv(base_url="https://<your-space>.hf.space") as env:
...🔌 REST API
# Reset into a scenario
curl -X POST "http://localhost:7860/api/reset?difficulty=hard&scenario_id=cascade_blackout"
# Step
curl -X POST http://localhost:7860/api/step \
-H "Content-Type: application/json" \
-d '{"action": [100, 0, 50, 45, 40, 28]}'
# List all scenarios
curl http://localhost:7860/api/scenarios
# List probe scenarios only
curl "http://localhost:7860/api/scenarios?probe_only=true"
# Scenario details
curl http://localhost:7860/api/scenarios/cascade_blackout
# Health
curl http://localhost:7860/health🔄 WebSocket (low-latency)
import websockets, json, asyncio
async def demo():
async with websockets.connect("ws://localhost:7860/ws") as ws:
await ws.send(json.dumps({
"type": "reset",
"difficulty": "hard",
"scenario_id": "cascade_blackout"
}))
result = json.loads(await ws.recv())
await ws.send(json.dumps({
"type": "step",
"action": [100, 0, 50, 45, 40, 28]
}))
result = json.loads(await ws.recv())
print(f"Reward: {result['reward']}")
asyncio.run(demo())🎮 Difficulty Levels
🏅 Reward — 6 Components, Range [-1, +1]
📁 Project Structure
power_grid/
├── env/
│ ├── ieee14.py # IEEE 14-bus topology constants
│ ├── dc_power_flow.py # B-matrix builder + DC linear solver
│ └── grid_env.py # PowerGridEnv: step/reset/state, relay, disturbances
├── scenarios/
│ ├── __init__.py
│ └── scenarios.py # 8 named crisis scenarios (probe + trainable)
├── agents/
│ └── baselines.py # RandomAgent, RuleBasedAgent, EconomicDispatchAgent
├── tasks/
│ └── graders.py # Per-difficulty episode grader (0–100, A–F)
├── tests/
│ └── test_env.py # 31 physics + contract + integration tests
├── server/
│ └── app.py # FastAPI REST + WebSocket + Gradio UI
├── client.py # PowerGridEnv async + sync client
├── models.py # Pydantic action/observation/state models
├── inference.py # Batch LLM evaluation → JSON results
├── scenario_config.json # Scenario runner configuration
├── validate.py # 13-check environment validator
├── Dockerfile
├── requirements.txt
└── openenv.yaml # OpenEnv 2.0 manifest🐳 Docker
docker build -t power-grid .
docker run --rm -p 7860:7860 power-grid
# Health check:
curl http://localhost:7860/health
# → {"status": "healthy", "service": "power-grid-env"}📈 Baseline Scores (RuleBasedAgent, seed=42, 3 episodes)
Reproduce:
python inference.py --agent rulebased --episodes 3 --seed 42Run LLM agent (requires HF_TOKEN environment variable):
python inference.py --episodes 3 --seed 42📜 License
MIT
