grid-royale / api.py
LokeshReddy001's picture
suchith's changes (#2)
d7e2b77
Raw
History Blame Contribute Delete
6.11 kB
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from backend.environment import GameConfig
from backend.engine import Engine
from backend.tools import TOOL_SCHEMAS
app = FastAPI(title="Grid Royale API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
engine: Engine | None = None
@app.on_event("startup")
async def _seed_default_game():
"""Pre-create a game so visitors see a live arena instead of a lobby."""
global engine
try:
cfg = GameConfig(grid_size=20, max_turns=100, max_agents=4, num_chests=15)
eng = Engine(config=cfg)
eng.generate_grid()
eng.scatter_chests()
for i, name in enumerate(_default_names(4)):
eng.spawn_agent(agent_id=f"agent_{i}", name=name)
engine = eng
except Exception as exc:
import logging
logging.getLogger("uvicorn.error").warning(f"Default game seed failed: {exc}")
class StartGameRequest(BaseModel):
grid_size: int = 20
max_turns: int = 50
max_agents: int = 8
num_chests: int = 15
agent_names: list[str] | None = None
system_prompt: str | None = None
system_prompts: dict[str, str] | None = None
def _serialize(aid: str) -> dict:
if not engine:
return {}
a = engine.env.agents[aid]
return {
"id": a.id,
"name": a.name,
"x": a.pos[0],
"y": a.pos[1],
"hp": a.hp,
"alive": a.alive,
"score": a.score,
"kills": a.kills,
"shielded": a.shielded,
"abilities": [
{"name": ab.name, "last_used_turn": ab.last_used_turn, "uses_remaining": ab.uses_remaining}
for ab in a.abilities
],
"messages": a.messages[-24:],
}
def _game_state() -> dict:
if not engine:
return {}
alive = engine.env.alive_agents()
tiles = {}
for (x, y), tile in engine.env.grid.items():
tiles[f"{x},{y}"] = {
"terrain": tile.terrain,
"loot": [
{
"type": item.type,
"ability_name": item.ability_name,
"points": item.points,
"rarity": item.rarity,
"source": item.source,
}
for item in tile.loot
] if tile.loot else [],
}
return {
"turn": engine.env.turn,
"grid_size": engine.env.config.grid_size,
"max_turns": engine.env.config.max_turns,
"agents": [_serialize(aid) for aid in engine.env.agents],
"tiles": tiles,
"game_over": len(alive) <= 1 or engine.env.turn >= engine.env.config.max_turns,
"winner": alive[0].name if len(alive) == 1 else None,
"turn_log": engine.last_turn_log,
"tool_schemas": TOOL_SCHEMAS,
}
BOT_NAMES = [
"Vex", "Nyx", "Kael", "Zara",
"Cypher", "Helix", "Apex", "Blaze",
]
def _default_names(count: int) -> list[str]:
return BOT_NAMES[:count]
@app.post("/api/game/start")
async def start_game(req: StartGameRequest):
global engine
config = GameConfig(
grid_size=req.grid_size,
max_turns=req.max_turns,
max_agents=req.max_agents,
num_chests=req.num_chests,
)
engine = Engine(config=config)
engine.generate_grid()
engine.scatter_chests()
names = req.agent_names or _default_names(req.max_agents)
for i, name in enumerate(names):
if i >= req.max_agents:
break
aid = f"agent_{i}"
prompt = None
if req.system_prompts:
prompt = req.system_prompts.get(aid) or req.system_prompts.get(name)
if not prompt:
prompt = req.system_prompt
engine.spawn_agent(agent_id=aid, name=name, system_prompt=prompt)
return {"message": f"Game started with {len(names)} agents", "turn": 0}
@app.post("/api/game/step")
async def game_step():
if not engine:
raise HTTPException(400, "No game running")
await engine.step()
return _game_state()
@app.get("/api/game/state")
async def game_state():
if not engine:
raise HTTPException(400, "No game running")
return _game_state()
@app.post("/api/game/run")
async def run_full_game(req: StartGameRequest):
global engine
config = GameConfig(
grid_size=req.grid_size,
max_turns=req.max_turns,
max_agents=req.max_agents,
num_chests=req.num_chests,
)
engine = Engine(config=config)
engine.generate_grid()
engine.scatter_chests()
names = req.agent_names or _default_names(req.max_agents)
for i, name in enumerate(names):
if i >= req.max_agents:
break
aid = f"agent_{i}"
prompt = None
if req.system_prompts:
prompt = req.system_prompts.get(aid) or req.system_prompts.get(name)
if not prompt:
prompt = req.system_prompt
engine.spawn_agent(agent_id=aid, name=name, system_prompt=prompt)
await engine.run_game()
return _game_state()
@app.get("/api/game/default_prompt")
def get_default_prompt(grid_size: int = 20):
from backend.agent.agent import Agent
return {"default_prompt": Agent.get_default_system_prompt(grid_size=grid_size)}
@app.post("/api/model/warm")
async def warm_model():
from backend.agent.llm_client import get_llm_client
try:
client = get_llm_client()
response = await client.chat.completions.create(
model="google/gemma-4-26B-A4B-it",
messages=[{"role": "user", "content": "ping"}],
max_tokens=5
)
if response and response.choices:
return {
"status": "success",
"message": "Model warmed up successfully!",
"response": response.choices[0].message.content
}
return {"status": "warning", "message": "No choices returned from model."}
except Exception as e:
return {"status": "error", "detail": str(e)}