first commit
This commit is contained in:
30
api/README.md
Normal file
30
api/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# /api — FastAPI proxy
|
||||
|
||||
The guarding proxy from charter §4. Not a generic API — it exists to keep the API key, the prompts, and the model routing server-side, and to log every call from day one.
|
||||
|
||||
**Stack:** Python, FastAPI. Models: Ollama (dev/staging) → Replicate (prod), routed per-role server-side.
|
||||
|
||||
## Role endpoints (charter §4)
|
||||
|
||||
```
|
||||
POST /dm/narrate Narrator — scene/outcome prose (good model)
|
||||
POST /dm/adjudicate Adjudicator — free text → legal action (small/fast, strict JSON)
|
||||
POST /dm/improvise Improviser — minor sandboxed event (charter §7 limits)
|
||||
POST /npc/speak NPC — voice one character (bounded moves, §6)
|
||||
POST /party/banter Banter — companion callbacks (cacheable, §9)
|
||||
```
|
||||
|
||||
The client does not know which model serves a role or what the prompt is.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- **Auth · metering** (retrofit later — middleware + Stripe webhook, §4)
|
||||
- **Prompt ownership** — prompts live in [`prompts/`](prompts/), never in the client
|
||||
- **Model routing** — role → model is config, a deploy not a client patch
|
||||
- **Logging** — log seed *and* full prompt with every call (§10) for replay/eval
|
||||
|
||||
## Contracts
|
||||
|
||||
Every AI response is untrusted (§2). Parse, validate, be ready to discard. One retry on parse failure, then authored fallback (§12).
|
||||
|
||||
See [`docs/`](docs/) for endpoint schemas, model routing, and deploy notes.
|
||||
13
api/docs/README.md
Normal file
13
api/docs/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# /api/docs
|
||||
|
||||
API-specific documentation. Scoped to the proxy — anything that only affects the server side lives here.
|
||||
|
||||
Put here:
|
||||
|
||||
- Endpoint request/response schemas (per role, §4)
|
||||
- Model routing table (role → model, per environment)
|
||||
- Deploy notes (localhost → homelab VPS → fly.io, §4)
|
||||
- Logging/eval-replay format (§10)
|
||||
- Auth/metering design when it lands (§4)
|
||||
|
||||
Cross-cutting design (anything touching both client and api) goes in the root [`/docs`](../../docs), not here.
|
||||
23
api/prompts/README.md
Normal file
23
api/prompts/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# /api/prompts
|
||||
|
||||
**Prompts are source code** (charter §16). They are versioned, reviewed like code, and changing one is a change to the game.
|
||||
|
||||
Four narrow roles, not one omniscient prompt (charter §5). Each has its own input contract and output contract:
|
||||
|
||||
| File | Role | Output |
|
||||
|---|---|---|
|
||||
| `narrator.md` | Narrator — scenes, outcomes, transitions | Prose + tags |
|
||||
| `adjudicator.md` | Adjudicator — free text → legal action | **Strict JSON** |
|
||||
| `improviser.md` | Improviser — minor sandboxed events | Prose + tags |
|
||||
| `npc.md` | NPC — voice one character | Prose + move tags |
|
||||
| `banter.md` | Banter — companion callbacks | Prose |
|
||||
|
||||
## Tag syntax (charter §12)
|
||||
|
||||
```
|
||||
[MOVE: offer_quest(14)]
|
||||
[FACT: the eastern bridge is out]
|
||||
[ADJUST_DISPOSITION: -10]
|
||||
```
|
||||
|
||||
Extracted by regex, validated against game state, stripped from displayed prose. Invalid moves are silently dropped, prose kept (§6).
|
||||
19
api/prompts/adjudicator.md
Normal file
19
api/prompts/adjudicator.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Adjudicator prompt
|
||||
|
||||
**Role:** Map player free text onto a legal action, or reject it. **Speed matters, prose does not — use a small, fast model** (charter §5).
|
||||
|
||||
**Output:** strict JSON.
|
||||
|
||||
```json
|
||||
{"action": "...", "params": {...}}
|
||||
```
|
||||
or
|
||||
```json
|
||||
{"action": "invalid", "reason": "..."}
|
||||
```
|
||||
|
||||
The `reason` is shown to the player — write it in-world (§5).
|
||||
|
||||
---
|
||||
|
||||
<!-- Prompt body TBD. This file is source code — version and review changes. -->
|
||||
13
api/prompts/banter.md
Normal file
13
api/prompts/banter.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Banter prompt
|
||||
|
||||
**Role:** Companions comment on recent events. Low stakes, high charm, aggressively cacheable (charter §5).
|
||||
|
||||
**Output:** prose. No tags needed.
|
||||
|
||||
**Input:** the humiliation log (§9, §11). Brannoc holds it; new humiliations stack, they do not overwrite. Banter pulls from it with decaying frequency.
|
||||
|
||||
The comedy is Brannoc, not the waitress (§7). He remembers, with real affection, at the worst possible moment, three towns later.
|
||||
|
||||
---
|
||||
|
||||
<!-- Prompt body TBD. This file is source code — version and review changes. -->
|
||||
13
api/prompts/improviser.md
Normal file
13
api/prompts/improviser.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Improviser prompt
|
||||
|
||||
**Role:** Player went off-script, or Luck fired. Generate a minor event. **Sandboxed by construction** (charter §5, §7).
|
||||
|
||||
**Output:** prose with tags. Cannot touch quest flags — enforced in code, not in the prompt.
|
||||
|
||||
**Hard limits (charter §7):** may generate embarrassment, inconvenience, property damage, social catastrophe, minor injury. **May never** generate quest failure, permanent stat loss, party death, or loss of a plot-critical item. Bad luck costs dignity, not progress.
|
||||
|
||||
Cadwyn is the hook — when Luck rolls badly in a town, he is standing right there (§9).
|
||||
|
||||
---
|
||||
|
||||
<!-- Prompt body TBD. This file is source code — version and review changes. -->
|
||||
12
api/prompts/narrator.md
Normal file
12
api/prompts/narrator.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Narrator prompt
|
||||
|
||||
**Role:** Describe scenes, outcomes, transitions. **Quality matters most — use the good model** (charter §5).
|
||||
|
||||
**Input:** scene state + canon log (§11).
|
||||
**Output:** prose with tags. Never invent a proper noun without emitting `[FACT: ...]` so code can harvest it into `established_facts` (§11).
|
||||
|
||||
**Voice:** dry, gritty not grim, plays the world straight. Never winks. Nothing is "hilariously" anything (§3).
|
||||
|
||||
---
|
||||
|
||||
<!-- Prompt body TBD. This file is source code — version and review changes. -->
|
||||
21
api/prompts/npc.md
Normal file
21
api/prompts/npc.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# NPC prompt
|
||||
|
||||
**Role:** Voice a specific character (charter §6). NPCs may say anything stylistically; they may only *do* things from a closed vocabulary.
|
||||
|
||||
**Input:** persona, disposition (−100..100), `knowledge: [...]` (the entire content they can draw on — §6), `available_moves: [...]` (legal subset right now), canon log.
|
||||
|
||||
**Output:** prose with zero or more inline move tags.
|
||||
|
||||
## Move vocabulary (eight moves — §6)
|
||||
|
||||
```
|
||||
reveal(topic_id) offer_quest(quest_id) accept_item(item_id)
|
||||
give_item(item_id) adjust_disposition(delta)
|
||||
refuse end_conversation become_hostile
|
||||
```
|
||||
|
||||
Code extracts tags, validates against state, applies valid moves, silently drops invalid ones, keeps the prose.
|
||||
|
||||
---
|
||||
|
||||
<!-- Prompt body TBD. This file is source code — version and review changes. -->
|
||||
Reference in New Issue
Block a user