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**:
```json
{
"seed": 42,
"episode_id": "optional-uuid-string"
}
```
**Response** (200 OK):
```json
{
"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**:
```json
{
"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):
```json
{
"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):
```json
{
"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:
```javascript
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`)
```javascript
{
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`)
```javascript
{
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**:
```json
{
"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
```javascript
// 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.