from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from models import BDOAction from server.bdo_environment import BDOEnvironment PROMPT = """ Enter a JSON action batch, for example: {"predicted_fraud_level": 0.4, "actions": [{"name": "allocate_funds", "params": {"village": "Loba", "amount": 5000}}, {"name": "approve_batch", "params": {"village": "Loba", "mode": "conservative"}}]} You can paste either a compact one-line JSON object or multi-line JSON. For multi-line input, paste the JSON and then submit an empty line. Type `quit` to exit. """.strip() def print_summary(observation: dict) -> None: print( f"Month {observation['meta']['month']} | " f"budget={observation['treasury']['district_budget']} | " f"reserve={observation['treasury']['buffer_reserve']} | " f"hours={observation['meta']['hours_remaining']} | " f"event={observation['meta']['global_event']}" ) for node in observation["nodes"]: print( f"- {node['village']}: reported={node['reported_demand']} " f"lag={node['report_lag_days']}d biometric={node['biometric_signal']} " f"stability={node['stability_index']}" ) if observation["high_risk_queue"]: print("High-risk queue:") for item in observation["high_risk_queue"]: print( f" {item['transfer_id']} {item['village']} amount={item['amount']} " f"flag={item['oversight_flag']}" ) def read_json_payload() -> str | None: first = input("> ").strip() if first.lower() in {"quit", "exit"}: return None if not first: return "" lines = [first] while True: candidate = "\n".join(lines) try: json.loads(candidate) return candidate except json.JSONDecodeError: try: next_line = input().rstrip() except EOFError: return candidate if not next_line.strip(): return candidate lines.append(next_line) def main() -> None: scenario = sys.argv[1] if len(sys.argv) > 1 else "calm_year" env = BDOEnvironment(scenario=scenario) observation = env.reset() print(f"Scenario: {scenario}") print("Episode info:", env.state.model_dump(mode="json", exclude_none=True)) while not observation.done: print("\nCurrent district snapshot:") print_summary(observation.model_dump(mode="json", exclude_none=True)) print() print(PROMPT) raw = read_json_payload() if raw is None: break try: json.loads(raw) except json.JSONDecodeError as exc: print(f"Invalid JSON: {exc}") continue observation = env.step(BDOAction.model_validate_json(raw)) step_info = observation.info or observation.metadata print(f"Reward: {float(observation.reward or 0.0):.4f}") print("Executed actions:") for item in step_info["executed_actions"]: print(f" - {item}") if step_info["truncated_actions"]: print("Truncated actions:", step_info["truncated_actions"]) if step_info["errors"]: print("Errors:", step_info["errors"]) print("Reward breakdown:", step_info["reward_breakdown"]) if __name__ == "__main__": main()