godseed / server /schemas.py
AndresCarreon's picture
GODSEED v0
0594db3 verified
Raw
History Blame Contribute Delete
2.35 kB
"""Pydantic request/response models for the GODSEED HTTP API.
Shapes follow ARCHITECTURE.md §HTTP API exactly:
GET /api/state -> StateResponse
POST /api/wish {text} -> WishAccepted (errors: 400/429/503 with a poetic `detail` string)
GET /api/wishes -> list[WishSummary]
GET /api/wishes/{id} -> raw WishTrace dict (passed through, engine-owned shape)
Features and WishTraces are deliberately NOT strict models here: the engine owns those
shapes and the server passes them through untouched (the "her" pattern — transport never
reinterprets world facts).
"""
from __future__ import annotations
from typing import Any, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator
# The moderation fast-path enforces the real wish limit (<=140 chars) with a poetic
# reason; this transport-level cap only stops abusive megabyte bodies before they
# reach moderation.
TRANSPORT_MAX_WISH_CHARS = 2000
class WishRequest(BaseModel):
"""Body of POST /api/wish."""
model_config = ConfigDict(str_strip_whitespace=True)
text: str = Field(..., min_length=1, max_length=TRANSPORT_MAX_WISH_CHARS)
@field_validator("text")
@classmethod
def _not_blank(cls, value: str) -> str:
if not value.strip():
raise ValueError("a wish needs words")
return value.strip()
class WishAccepted(BaseModel):
"""Response of POST /api/wish."""
wish_id: str
position: int = Field(..., ge=1, description="1-based place in the queue")
class CurrentWish(BaseModel):
"""The wish the god is granting right now."""
wish_id: str
text_preview: str
class QueueInfo(BaseModel):
length: int = 0
current: Optional[CurrentWish] = None
class WorldState(BaseModel):
"""Snapshot of the deterministic world: ordered feature list + counters."""
version: int = Field(..., ge=0, description="total number of features")
epoch: int = Field(..., ge=0, description="number of granted wishes")
features: list[dict[str, Any]]
class WishSummary(BaseModel):
"""One row of the Genesis Log index (GET /api/wishes)."""
wish_id: str
text: str
epitaph: str = ""
epoch: int
ts: float
class StateResponse(BaseModel):
"""GET /api/state."""
world: WorldState
queue: QueueInfo
wishes_recent: list[WishSummary]