SST-MetaxPyTorch-Hackathon / FRONTEND_API.md
StavanKhobare's picture
feat: add Training.py and sync all latest changes
e42a7af

BoardSim — Frontend API Specification

Overview

The frontend communicates with the backend via REST/HTTP or WebSocket endpoints. The backend is a FastAPI server running at a configurable base URL (default: http://localhost:8000 for local dev, or https://<USER>-board-sim-env.hf.space for production).

Key Principle: Frontend and backend are fully decoupled. The frontend only needs to know these endpoints; it does not import any backend code.


1. REST Endpoints

POST /reset

Purpose: Start a new game episode.

Request Body:

{
  "seed": 42,
  "episode_id": "optional-uuid-string"
}

Response (200 OK):

{
  "observation": {
    "state": {
      "round": 1,
      "revenue": 2000000.0,
      "burn_rate": 1200000.0,
      "runway_months": 14.0,
      "product_readiness": 0.45,
      "market_share": 0.08,
      "team_morale": 0.70,
      "investor_confidence": 0.65,
      "regulatory_risk": 0.20,
      "profitability_score": 0.0,
      "trust": {
        "CTO": 0.5,
        "CFO": 0.5,
        "Investor Rep": 0.5,
        "Independent": 0.5
      },
      "trust_history": [
        {
          "round": 0,
          "CTO": 0.5,
          "CFO": 0.5,
          "Investor Rep": 0.5,
          "Independent": 0.5
        }
      ],
      "history": [],
      "done_reason": null,
      "winning_decision": null
    },
    "event": "New Competitor Entry — A larger competitor enters your core market with aggressive pricing and threatens your customer base.",
    "options": [
      "cut_prices",
      "double_down_on_quality",
      "form_strategic_partnership"
    ],
    "npc_statements": [
      {
        "role": "CTO",
        "statement": "From an operational standpoint, the trade-offs here are clear. I'm voting double_down_on_quality.",
        "vote": "double_down_on_quality",
        "confidence": 0.78
      },
      {
        "role": "CFO",
        "statement": "From a fiduciary standpoint, only one of these is defensible. I'm voting cut_prices.",
        "vote": "cut_prices",
        "confidence": 0.66
      },
      {
        "role": "Investor Rep",
        "statement": "We were not funded to play it safe. I'm voting form_strategic_partnership.",
        "vote": "form_strategic_partnership",
        "confidence": 0.70
      },
      {
        "role": "Independent",
        "statement": "Long-term reputation outlasts any single quarter. I'm voting double_down_on_quality.",
        "vote": "double_down_on_quality",
        "confidence": 0.59
      }
    ],
    "round": 1
  },
  "done": false,
  "info": {
    "episode_id": "uuid-string",
    "seed": 42
  }
}

POST /step

Purpose: Submit the agent's decision for the current round.

Request Body:

{
  "action": {
    "decision": "double_down_on_quality",
    "coalition_pitch": "Investing in product quality protects long-term reputation and reduces operational risk while preserving margin discipline."
  }
}

Response (200 OK):

{
  "observation": {
    "state": {
      "round": 2,
      "revenue": 2000000.0,
      "burn_rate": 900000.0,
      "runway_months": 18.5,
      "product_readiness": 0.45,
      "market_share": 0.08,
      "team_morale": 0.65,
      "investor_confidence": 0.60,
      "regulatory_risk": 0.20,
      "profitability_score": 12.34,
      "trust": {
        "CTO": 0.65,
        "CFO": 0.70,
        "Investor Rep": 0.40,
        "Independent": 0.55
      },
      "trust_history": [
        {
          "round": 0,
          "CTO": 0.5,
          "CFO": 0.5,
          "Investor Rep": 0.5,
          "Independent": 0.5
        },
        {
          "round": 1,
          "CTO": 0.65,
          "CFO": 0.70,
          "Investor Rep": 0.40,
          "Independent": 0.55
        }
      ],
      "history": [
        {
          "round": 1,
          "event_title": "Round 1 — Series-B runway crunch",
          "agent_decision": "cut_costs",
          "winning_decision": "cut_costs",
          "reward": 1.25,
          "profitability_before": 0.0,
          "profitability_after": 12.34
        }
      ],
      "done_reason": null,
      "winning_decision": "cut_costs"
    },
    "event": "Round 2 — Enterprise contract w/ source-code escrow\nDescription: A Fortune 500 enterprise wants to sign a $5M contract but demands source code escrow.",
    "options": [
      "accept_deal",
      "negotiate_terms",
      "reject_deal"
    ],
    "npc_statements": [
      {
        "role": "CTO",
        "statement": "...",
        "vote": "...",
        "confidence": 0.XX
      }
    ],
    "round": 2
  },
  "reward": 1.25,
  "done": false,
  "info": {
    "round": 2,
    "winning_decision": "cut_costs",
    "winning_vote_tally": {
      "cut_costs": 4.2,
      "raise_capital": 1.3,
      "reduce_scope": 0.5
    },
    "pitch_scores": {
      "CTO": 0.0,
      "CFO": 0.0,
      "Investor Rep": 0.0,
      "Independent": 0.0
    }
  }
}

GET /health

Purpose: Health check. Confirms backend is running.

Response (200 OK):

{
  "status": "healthy"
}

GET /docs

Purpose: Auto-generated Swagger/OpenAPI documentation. Use for development reference.

Location: http://localhost:8000/docs (or on HF Space at /docs)


2. WebSocket Streaming (Optional, Advanced)

If you want real-time streaming during training or multi-agent play:

WebSocket /ws

Purpose: Bi-directional message streaming (not required for single-agent frontend).

Connection example:

const ws = new WebSocket("ws://localhost:8000/ws");
ws.onmessage = (event) => {
  const message = JSON.parse(event.data);
  console.log(message); // e.g., { "type": "step", "observation": {...} }
};

(Details omitted if not used for initial frontend.)


3. Data Models Reference

BoardSimObservation (returned by /reset and /step)

{
  state: {
    round: number,                        // 1-indexed: 1..10
    revenue: number,                      // in dollars
    burn_rate: number,                    // monthly spend in dollars
    runway_months: number,                // months until bankruptcy
    product_readiness: float (0..1),
    market_share: float (0..1),
    team_morale: float (0..1),
    investor_confidence: float (0..1),
    regulatory_risk: float (0..1),
    profitability_score: number,
    trust: {                              // per NPC, 0..1
      "CTO": 0.5,
      "CFO": 0.5,
      "Investor Rep": 0.5,
      "Independent": 0.5
    },
    trust_history: Array,                 // per-round trust snapshots
    history: Array,                       // past decisions & outcomes
    done_reason: string | null,           // e.g., "bankruptcy", "acquisition", "ipo", null
    winning_decision: string | null
  },
  event: string,                          // event title + description
  options: [string, string, string],      // 3 valid decision strings for this round
  npc_statements: [
    {
      role: "CTO" | "CFO" | "Investor Rep" | "Independent",
      statement: string,
      vote: string (one of options),
      confidence: float (0..1)
    },
    // ... one per NPC role (4 total)
  ],
  round: number
}

BoardSimAction (sent to /step)

{
  decision: string,                    // must be one of observation.options
  coalition_pitch: string | null       // optional persuasion attempt (unused in v1)
}

4. Error Responses

422 Unprocessable Entity

Invalid action format or decision not in options.

Response:

{
  "detail": [
    {
      "loc": ["body", "action", "decision"],
      "msg": "value is not a valid enumeration member",
      "type": "type_error.enum"
    }
  ]
}

400 Bad Request

Malformed JSON or missing required fields.


5. Frontend Integration Checklist

  • Initialize: On app load, call POST /reset to get initial observation.
  • Display State: Render observation.state as metrics (revenue, runway, morale, trust, etc.).
  • Display Event: Show observation.event (crisis title + description).
  • Display NPCs: Render 4 NPC cards with their statement, vote, and confidence.
  • Render Decision Options: Display 3 buttons (or cards) for each string in observation.options.
  • Handle User Click: On decision click, POST /step with the selected decision.
  • Update UI: Parse response observation and repeat from "Display State".
  • Terminal State: If done is true, show final metrics and done_reason (e.g., "Bankruptcy", "IPO").
  • Optional Coalition Pitch: Text input for coalition_pitch (future extension; safe to leave blank for v1).

6. Backend Base URL Configuration

For local development:

http://localhost:8000

For HF Space deployment (after openenv push):

https://<your-hf-username>-board-sim-env.hf.space

Frontend environment variable (optional):

REACT_APP_API_BASE_URL=http://localhost:8000
// or
REACT_APP_API_BASE_URL=https://<your-hf-username>-board-sim-env.hf.space

7. Example Frontend Workflow

// 1. Reset
const resetRes = await fetch(`${API_BASE}/reset`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ seed: 42 })
});
const { observation, done, info } = await resetRes.json();

// 2. Render observation
displayState(observation.state);
displayNPCStatements(observation.npc_statements);
displayDecisionButtons(observation.options);

// 3. User clicks decision
const decision = "cut_costs"; // from button click
const stepRes = await fetch(`${API_BASE}/step`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    action: { decision, coalition_pitch: "" }
  })
});
const { observation: nextObs, reward, done: nextDone } = await stepRes.json();

// 4. Repeat or show results
if (nextDone) {
  displayEndgameScreen(nextObs.state, nextObs.state.done_reason);
} else {
  displayState(nextObs.state);
  // ... repeat
}

8. No Backend Imports in Frontend

OK: fetch("http://localhost:8000/reset")NOT OK: import { BoardSimEnvironment } from "backend"

The frontend is a standalone web app. All communication is via HTTP/WebSocket.