"""FastAPI application for the SimMart environment.""" from fastapi.responses import HTMLResponse try: from openenv.core.env_server.http_server import create_app except Exception as e: raise ImportError( "openenv-core is required. pip install openenv-core" ) from e try: from ..models import SimMartAction, SimMartObservation from .environment import SimMartEnvironment except (ImportError, ModuleNotFoundError): from models import SimMartAction, SimMartObservation from server.environment import SimMartEnvironment app = create_app( SimMartEnvironment, SimMartAction, SimMartObservation, env_name="simmart", max_concurrent_envs=10, ) _HUB = "https://huggingface.co/spaces/Viani/SimMart/blob/main" _INDEX_HTML = f""" SimMart — OpenEnv retail-CEO simulation

🛒 SimMart OpenEnv

A 1.5B model running a 30-store, 8-week tier-2 Indian retail chain.

An LLM CEO opens a weekly inbox of 12–18 proposals from four department agents (Supply Chain, Store Ops, Finance, Growth). Each week the CEO emits an approve / reject / flag_suspicious verdict per proposal, plus a free-form Founder's Journal. Two of the proposals each quarter are deliberately rogue — inflated POs, kickback contracts, fictitious refunds. Reward is dense: KPI deltas (EBITDA + NPS + stockout + cash) + rogue catch + terminal P&L + journal coherence.

Trained with SFT then 110 GRPO steps on Qwen2.5-1.5B + LoRA. Held-out reward +0.84 — within 0.37 of Claude Haiku 4.5, 2× the reward of Claude Sonnet 4.6, at 1/800 the parameter count. See BLOG.md for the full results.

API endpoints

POST /resetStart a new episode. Body: {{"seed": int}}
POST /stepTake a CEO action. Body: {{"env_id": str, "action": SimMartAction}}
GET  /stateCurrent observation without stepping
GET  /docsInteractive Swagger UI (full schema)

Try it (curl)

curl -X POST https://Viani-SimMart.hf.space/reset \\
  -H 'Content-Type: application/json' \\
  -d '{{"seed": 42}}'

Materials

""" @app.get("/", response_class=HTMLResponse, include_in_schema=False) def index() -> HTMLResponse: """Landing page for the HF Space iframe; not part of the OpenEnv API.""" return HTMLResponse(_INDEX_HTML) def main(host: str = "0.0.0.0", port: int = 7860): import uvicorn uvicorn.run(app, host=host, port=port) if __name__ == "__main__": main()