Spaces:
Running
A newer version of the Gradio SDK is available: 6.19.0
OpenRA-Bench → Unified Eval Stack Plan
Goal
Turn OpenRA-Bench into an efficient, customizable harness to evaluate model performance on spatial, multi-modal, and complex multi-target multi-step reasoning / planning, by reusing the mature eval stack from OpenRA-RL-Training on top of the Rust environment (OpenRA-Rust).
Two evaluation modes:
- Fixed-scenario eval — N episodes of one model on a controlled scenario, scored with verifiable rubrics + composite score + 95% CIs.
- Pairwise adversarial 1v1 — two models in one 1v1 map, win-rate / Elo.
Scenarios must be controlled and isolate specific capabilities (e.g. the observed failure: model cannot connect an unexplored region to a target area to explore — a vision/perception + spatial-planning deficiency).
Core framing: the Perception → Reasoning → Action chain
Every scenario evaluates one chain: read the (visual + symbolic) state → form a multi-step plan → emit valid commands that execute it. The eval must attribute failure to a specific link, not just report a score:
- Perception — did the model correctly read the minimap/state? (e.g. locate the unexplored region and the target). Probe via state-readback / forced-choice checks derived from ground-truth obs.
- Reasoning — given correct perception, did it form a valid plan? (e.g. connect unexplored→target, sequence multi-target order). Probe via plan quality vs optimal (path length, target ordering, sub-goal coverage).
- Action — did it emit syntactically/semantically valid commands that realize the plan? Probe via action-validity rate and plan↔execution drift.
Per-scenario rubrics carry one diagnostic per link so a low score points at the broken link. This is the primary product differentiator vs a raw win-rate bench.
Decisions (locked)
- Repo: refactor OpenRA-Bench in place; it imports Training's eval stack. OpenRA-RL-Training stays source of truth for the engine code.
- Backend: Rust only (
openra_trainPyO3). C# (openra-rl) is slow/fragile and is dropped from the eval path. Rust must be made faithful to the C# reference where scenarios require it. - Multi-modal: reuse Training's
minimap_renderer.render_minimap()PNG, injected asimage_urlin the agent prompt.
Source components reused from OpenRA-RL-Training
| Component | Path | Role in Bench |
|---|---|---|
| Episode engine | openra_rl_training/training/agent_rollout.py (play_episodes_async) |
Drives the real model loop (currently Bench's agent fn is a no-op) |
| Reward dims | training/reward_funcs.py |
Per-scenario weighted scoring |
| Rust pool | training/rust_env_pool.py |
The only backend |
| Minimap | training/minimap_renderer.py |
Multi-modal observation |
| Scenarios/rubrics | scenarios/*.yaml, curricula/*.yaml, verifiable metrics |
Controlled tasks + pass/fail |
| CI comparison | scripts/build_eval_comparison.py |
Stat-sound model comparison |
Rust faithfulness gap (drives sequencing)
- Commands: 3/22 (Move, Attack, Observe). Missing: Build/Train/Harvest/Deploy/ Sell/Repair/Stance/Transport/Power/RallyPoint/Guard/Patrol…
- Observations: ~30% of C# proto. Missing: economy, production, military stats, spatial tensor, kill_events, result/reward fields.
- Scenarios: 2 hand-built (rush-hour, scout-maginot). No generic
.oramapload. - Engine: movement (A*), combat, projectiles, fog, static defenses = done. Economy, production/tech, transport, multi-armament = not done.
→ Movement/combat/fog scenarios + combat-only 1v1 work today. Economy / production / tech scenarios require Rust engine work first.
CRITICAL FINDING (verified end-to-end, local)
play_episodes_async (agent_rollout.py:4815) is hardwired to the C# gRPC
server via openra_env.mcp_ws_client.OpenRAMCPClient and is entangled with
TRL (tokenizer, prompt_ids/completion_ids, worker pool, partial cache). It is
not reusable as-is on Rust. rust_env_pool is used only by the lighter
rollout.py path.
Also: minimap_renderer.render_minimap() expects state["minimap"] (ASCII),
units_summary, enemy_summary — none of which the Rust env emits.
Verified live Rust obs schema (openra_train rush-hour, local wheel,
Python 3.12, anaconda):
keys = enemy_buildings_summary, enemy_hp, enemy_positions, explored_cells,
explored_percent, game_tick, unit_hp, unit_positions, units_killed
unit_positions = {actor_id: {cell_x, cell_y[, target, activity, ...]}}
step() -> (obs, reward=0.0 hardcoded, done:bool, info={game_tick, warnings})
No minimap ASCII, no economy/military/result/reward, no terrain.
Consequence: Phase 0 builds a Bench-side episode loop that reuses
components (reward_funcs, minimap_renderer, scenario loader, action parser)
behind a Rust→schema adapter (openra_bench/rust_adapter.py). The adapter
is the crux and overlaps directly with the "make Rust faithful" workstream:
unit_positions→units_summary(renderer/prompt schema)enemy_positions+enemy_buildings_summary→enemy_summary- synthesize ASCII
minimapfromexplored_cells+ scenario map dims - load
terrain_pngfrom the scenario's base.oramap(as Training does) - derive scoring signals (kills, discovery, exploration, outcome) from obs
deltas since Rust
rewardis hardcoded 0.0 — feeds reward_funcs + the P/R/A diagnostics directly.
Target Bench layout
OpenRA-Bench/
openra_bench/
eval_core.py # thin wrapper over play_episodes_async, Rust backend forced
agent.py # REAL model agent (OpenAI-compatible), minimap multimodal
scenarios/ # controlled eval scenarios (symlink/copy + Bench-authored)
rubrics.py # verifiable + composite scoring (reuse Training)
pairwise.py # 1v1 adversarial orchestration + Elo
evaluate.py # fixed-scenario CLI (rewritten to use eval_core)
compare.py # CI comparison front-end (wraps build_eval_comparison)
app.py # leaderboard (fed by both modes)
Phases
Phase 0 — Integration spine (no Rust changes)
- Bench depends on
openra_rl_training+openra_train. eval_core.py: wrapplay_episodes_async, force Rust pool.agent.py: real OpenAI-compatible model agent w/ minimap PNG.- Rewrite
evaluate.py→ fixed-scenario eval producingeval_stats.json. compare.py→ 95% CI tables. Wire results intoapp.pyleaderboard.- Validate on rush-hour + scout-maginot (these are the perception tasks).
Phase 1 — Adversarial 1v1 (combat-only, current mechanics)
- Rust: add a second RL-controlled player slot in a 1v1 map (both sides accept Commands; remove scripted-enemy assumption).
- Bench
pairwise.py: two-model orchestration, win-rate + Elo, leaderboard.
Phase 2 — Controlled scenario library (current mechanics)
- Author perception/spatial scenarios that isolate the unexplored→target connection failure; maze/chokepoint pathfinding; multi-target prioritization.
- Verifiable rubrics per scenario (intelligence_pct, path-optimality, etc.).
Phase 3 — Rust mechanics expansion (unlocks scenario families)
- 3a Economy: ore/cash/harvester obs + HARVEST cmd + economy reward.
- 3b Production/tech: production queue, BUILD/TRAIN, available_production, power.
- Each sub-phase ships its scenario family + rubrics.
Test coverage (live engine, no mocks)
tests/test_rust_integration.py — 17 tests, ~1.9s, boots real
openra_train with rule-based bots (idle / charge / hunter):
- tool correctness: move_units reaches target; idle units hold; attack path; reset schema; same-seed determinism (bit-for-bit).
- corner cases: empty command list, invalid unit id (warns, no raise), invalid attack target, out-of-bounds move — all safe.
- invariants: explored% and units_killed monotonic non-decreasing; discovery set cumulative.
- stack: adapter signal tracking; win-condition predicates + composites
- unknown-key rejection; deterministic win/fail plumbing (trivially true win/fail conditions ⇒ exact outcome, not bot-skill dependent); all authored packs run end-to-end.
Sequencing (locked)
Phase 0 → Phase 2 (+ P/R/A diagnostics) → Phase 1 → Phase 3
Scenario breadth + per-link diagnostics first: fastest path to exposing real model strengths/weaknesses on current Rust mechanics. Adversarial 1v1 and the economy/production engine work follow.
Model provider abstraction (Phase 0)
openra_bench/agent.py exposes a provider-agnostic agent. Adapters:
- openai-compatible (default): covers local vLLM (matches Training's rollout
path) and OpenRouter (test target). Same Chat Completions + multimodal
image_urlfor the minimap PNG. Base URL + key from config/env. - bedrock: separate adapter (AWS SDK / Converse API), added when needed.
Selected via Bench config (provider, base_url, model, api_key_env).
Phase 0 validates with OpenRouter.