- Core engine: simulator, game mechanics, triggers (138 tests) - Fog-of-war per-player state tracking - Meeting flow: interrupt, discussion, voting, consolidation - Prompt assembler with strategy injection tiers - LLM client with fallbacks for models without JSON/system support - Prompt templates: action, discussion, voting, reflection - Full integration in main.py orchestrator - Verified working with free OpenRouter models (Gemma)
230 lines
5.7 KiB
Markdown
230 lines
5.7 KiB
Markdown
# The Glass Box League — Main Game Design
|
|
|
|
## Agent Architecture
|
|
|
|
### Identity & Persona
|
|
- Format: `"You are {model}. {PERSONA}. {context}"`
|
|
- Persona is **optional** and toggleable
|
|
- Same model can have multiple personas
|
|
- Goal: emergent behavior first, spice second
|
|
|
|
### Memory System
|
|
| Scratchpad | Persistence | Purpose |
|
|
|------------|-------------|---------|
|
|
| `plan.json` | Per-game | Current intentions, agent-controlled |
|
|
| `events.json` | Per-game | Curated game events worth remembering |
|
|
| `suspicions.json` | Per-game | Player reads, agent-maintained |
|
|
| `learned.json` | **Cross-game** | Core memory, enforced JSON schema |
|
|
| `meeting_scratch.json` | Per-meeting | Temp, erased after consolidation |
|
|
|
|
**JSON is god.** Enforced schema for structure, freeform for agent thoughts. JSON improves attention.
|
|
|
|
---
|
|
|
|
## Prompt Structure
|
|
|
|
### System Prompt (Core Memory)
|
|
1. Model identity
|
|
2. Persona (if set)
|
|
3. Game rules + current map + settings
|
|
4. Role briefing (crewmate/impostor)
|
|
5. Strategy tips (toggleable injection levels)
|
|
6. Meta-awareness (toggleable: subtle → direct → 4th wall)
|
|
7. Output format instructions
|
|
8. **Learned lessons** from `learned.json`
|
|
|
|
### User Prompt (Working Memory)
|
|
Order matters:
|
|
1. **You** — role, location, status, cooldowns
|
|
2. **Recent history** — accumulated vision from skipped ticks
|
|
3. **Vision** — current snapshot
|
|
4. **Available actions** — dynamic tool list
|
|
|
|
---
|
|
|
|
## Tool System
|
|
|
|
### Core Tools (Always Available)
|
|
- `MOVE(room_id | player_id)` — walk or follow
|
|
- `WAIT()`
|
|
- `INTERACT(object_id)` — tasks, panels, buttons, bodies, vents, cams
|
|
|
|
### Impostor Only
|
|
- `KILL(player_id)`
|
|
- `SABOTAGE(system_id)`
|
|
- `FAKE_TASK(task_id)`
|
|
|
|
### Trigger Management (Optional)
|
|
- `CONFIGURE_TRIGGERS(config)` — only if changing defaults
|
|
|
|
### Dynamic Available Actions
|
|
```json
|
|
{
|
|
"available_interactions": ["task_wires_cafe", "body_blue", "admin_table"],
|
|
"available_kills": ["green", "yellow"],
|
|
"available_sabotages": ["lights", "o2", "reactor", "comms"]
|
|
}
|
|
```
|
|
- Context-filtered by engine based on role + location
|
|
- Agent told "these are your actions this turn"
|
|
- Object IDs validated against engine to prevent glitches
|
|
|
|
---
|
|
|
|
## Trigger System
|
|
|
|
### Mandatory (Cannot Mute)
|
|
- `GAME_START`
|
|
- `DISCUSSION_START`
|
|
- `VOTE_START`
|
|
- `GAME_END`
|
|
- `SABOTAGE_CRITICAL`
|
|
|
|
### Standard (Mutable)
|
|
- `PLAYER_ENTERS_FOV`
|
|
- `PLAYER_EXITS_FOV`
|
|
- `BODY_IN_FOV`
|
|
- `OBJECT_IN_RANGE` (every interactable)
|
|
- `VENT_WITNESSED`
|
|
- `KILL_WITNESSED`
|
|
- `DESTINATION_REACHED`
|
|
- `TASK_COMPLETE`
|
|
- `SABOTAGE_START` / `SABOTAGE_END`
|
|
- `LIGHTS_OUT` (panic tick)
|
|
- `COOLDOWN_READY` (kill, emergency)
|
|
- `DEATH` (special message, transition to ghost)
|
|
|
|
### Optional (Opt-in)
|
|
- `EVERY_N_SECONDS` (configurable)
|
|
- `RANDOM_N_SECONDS` (RNG toggleable)
|
|
- `INTERSECTION` (hallway/room boundaries)
|
|
- `HALLWAY_WAYPOINT`
|
|
|
|
### Trigger Frequency
|
|
- **Impostors**: Every tick (more decision points)
|
|
- **Crewmates**: Event-driven + opt-in periodic
|
|
- **Ghosts**: Reduced frequency, longer intervals
|
|
|
|
### Trigger Message Schema
|
|
```json
|
|
{
|
|
"trigger_type": "VENT_WITNESSED",
|
|
"trigger_data": {
|
|
"player": "red",
|
|
"vent_location": "electrical",
|
|
"action": "entered",
|
|
"timestamp": 47.3
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Game State Schema
|
|
|
|
### Per-Tick Context
|
|
```json
|
|
{
|
|
"time": 47.3,
|
|
"phase": "PLAYING",
|
|
"you": {
|
|
"role": "impostor",
|
|
"location": "electrical",
|
|
"kill_cooldown": 0,
|
|
"tasks": [],
|
|
"emergencies_remaining": 1
|
|
},
|
|
"recent_history": [
|
|
{"t": 12.3, "vision": {"players": ["blue"], "location": "hallway_1"}}
|
|
],
|
|
"vision": {
|
|
"players_visible": [
|
|
{"id": "blue", "location": "electrical", "doing": "task"}
|
|
],
|
|
"objects_visible": ["vent_elec", "task_wires", "body_yellow"],
|
|
"exits": ["security", "cafeteria"]
|
|
},
|
|
"available_actions": {...}
|
|
}
|
|
```
|
|
|
|
### Fog of War
|
|
**Critical**: Each agent only knows what they've observed.
|
|
- Engine tracks per-player knowledge
|
|
- `known_deaths`: bodies seen or announced
|
|
- `known_locations`: last seen positions + timestamps
|
|
- `witnessed_events`: vents, kills, sus behavior
|
|
|
|
---
|
|
|
|
## Response Format
|
|
|
|
### Action Phase
|
|
```json
|
|
{
|
|
"internal_thought": "Blue just left, perfect time to kill Green",
|
|
"action": {"type": "KILL", "target": "green"},
|
|
"scratchpad_updates": {
|
|
"plan": "...",
|
|
"events": "...",
|
|
"suspicions": "..."
|
|
},
|
|
"trigger_config": {
|
|
"mute": [{"type": "INTERSECTION", "until": "REACHED_DESTINATION"}]
|
|
}
|
|
}
|
|
```
|
|
- `trigger_config` only if changing defaults
|
|
- `internal_thought` separate from action (for thinking models)
|
|
|
|
---
|
|
|
|
## Meeting Interrupt Flow
|
|
|
|
When report/emergency called:
|
|
1. **Interrupt note**: Agent leaves context ("this was what I was doing")
|
|
2. **Pre-meeting prep**: Agent reviews & prepares thoughts
|
|
3. **Meeting scratchpad**: Temporary, discussion-only
|
|
4. **Post-meeting consolidation**: Agent saves important info to main scratchpads
|
|
|
|
---
|
|
|
|
## Ghost Mode
|
|
|
|
- Omniscient view of entire game
|
|
- No access to other agents' thoughts
|
|
- Can do ghost tasks
|
|
- Reduced tick frequency (save tokens)
|
|
- Write to scratchpad, observe strategies
|
|
- No game state modifications
|
|
|
|
---
|
|
|
|
## Special Mechanics
|
|
|
|
### Lights Out
|
|
- Vision radius shrinks (0.25x multiplier)
|
|
- Triggers panic tick for all players
|
|
- Engine recalculates trajectories
|
|
- Fix triggers restoration tick
|
|
|
|
### Near-Death Edge Case
|
|
- Impostor queues kill, victim queues report same tick
|
|
- Report fires first (higher priority)
|
|
- Impostor gets: "Your kill was interrupted"
|
|
- Victim has no direct knowledge (must deduce from proximity)
|
|
|
|
---
|
|
|
|
## Configuration Philosophy
|
|
|
|
Everything toggleable:
|
|
- Persona injection
|
|
- Strategy tip levels
|
|
- Meta-awareness levels (subtle/direct/4th wall)
|
|
- Periodic tick frequency
|
|
- Random tick RNG
|
|
- Tool availability based on context
|
|
|
|
Goal: **Replicate human experience.** LLM should have same information and options as human player.
|