- 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)
188 lines
4.5 KiB
Markdown
188 lines
4.5 KiB
Markdown
# The Glass Box League — Discussion Phase Design
|
|
|
|
## Overview
|
|
|
|
Discussion phase follows real Among Us logic. Tick-based with priority bidding, vote-when-ready with gentle pressure, full transcript visibility.
|
|
|
|
---
|
|
|
|
## Discussion Tick Flow
|
|
|
|
### Each Tick, All Agents Submit:
|
|
```json
|
|
{
|
|
"internal_thought": "Red is deflecting hard, classic impostor",
|
|
"desire_to_speak": 7,
|
|
"message": "Red, you haven't explained where you were during lights",
|
|
"target": "red",
|
|
"vote_action": null,
|
|
"scratchpad_updates": {
|
|
"meeting_scratch": "Red avoiding questions. Blue quiet."
|
|
}
|
|
}
|
|
```
|
|
|
|
- `desire_to_speak`: 0-10 urgency
|
|
- `target`: Optional, who they're addressing
|
|
- `vote_action`: `null` (keep discussing), `"player_id"` (vote), or `"skip"`
|
|
- If `vote_action` set: locked in, but can still speak (slightly lower priority)
|
|
|
|
---
|
|
|
|
## Priority Bidding
|
|
|
|
### Priority Calculation:
|
|
```
|
|
base = desire_to_speak
|
|
+ mention_boost (if name appeared in recent messages)
|
|
+ accusation_boost (if directly targeted)
|
|
+ silence_boost (if haven't spoken in N ticks)
|
|
+ random(1, 6)
|
|
- recent_speaker_penalty (if just spoke)
|
|
- voted_penalty (if already voted, small)
|
|
```
|
|
|
|
### Winner Selection:
|
|
- Highest priority speaks
|
|
- Their `message` goes to transcript
|
|
- Repeat next tick
|
|
|
|
### Forced Participation:
|
|
- `silence_boost` increases each tick of silence
|
|
- Eventually forces even quiet players to speak
|
|
- "You can't just be silent, that ruins the fun"
|
|
|
|
---
|
|
|
|
## Vote Mechanics
|
|
|
|
### Actions:
|
|
- `VOTE(player_id)` — commit vote
|
|
- `SKIP_VOTE()` — commit skip
|
|
- Stay silent — keep discussing
|
|
|
|
### End Condition:
|
|
- All living players have voted → tally & reveal
|
|
- Pressure nudge if discussion runs long: `"System: wrap it up"`
|
|
- No hard round limit (hoping for convergence)
|
|
|
|
### Tie:
|
|
- No eject (real Among Us logic)
|
|
|
|
### Vote Lock:
|
|
- Once submitted, cannot change (real Among Us logic)
|
|
|
|
---
|
|
|
|
## Transcript Handling
|
|
|
|
### Visibility:
|
|
- Full transcript, JSON formatted
|
|
- All agents see everything said so far
|
|
- Target: keep under ~25k tokens
|
|
|
|
### Format:
|
|
```json
|
|
{
|
|
"transcript": [
|
|
{"speaker": "red", "message": "I was in electrical doing wires", "t": 0},
|
|
{"speaker": "blue", "message": "I saw Red near the body", "t": 1},
|
|
{"speaker": "red", "target": "blue", "message": "That's a lie!", "t": 2}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Pressure:
|
|
- If transcript gets too long, system nudges voting
|
|
- Agents feel urgency to wrap up
|
|
|
|
---
|
|
|
|
## Mention/Accusation Detection
|
|
|
|
- Simple string match on player color names
|
|
- If your name appears in message → `mention_boost`
|
|
- If message contains accusatory language toward you → `accusation_boost`
|
|
- Engine handles detection, agents don't need to flag
|
|
|
|
---
|
|
|
|
## Post-Vote Flow
|
|
|
|
### Reveal:
|
|
- Same as human would see in Among Us
|
|
- One by one reveal (dramatic)
|
|
- `confirm_ejects` setting: "Red was An Impostor" vs "Red was ejected"
|
|
|
|
### Reaction Tick:
|
|
- All agents get reaction tick after reveal
|
|
- Can update scratchpads, process result
|
|
|
|
### Consolidation Tick:
|
|
- Save important meeting info to main scratchpads
|
|
- Meeting scratchpad erased after this
|
|
|
|
---
|
|
|
|
## Ghost Chat
|
|
|
|
- Dead players can watch discussion
|
|
- Ghost chat separate from main discussion
|
|
- Useful for commentary/entertainment value
|
|
- Ghosts see full game state (omniscient)
|
|
- Cannot influence living players
|
|
|
|
---
|
|
|
|
## Impostor Discussion Strategy
|
|
|
|
### Prompt Reminders:
|
|
- "You are allowed to lie"
|
|
- "Construct alibis"
|
|
- "Deflect suspicion"
|
|
- "You know fellow impostors — don't expose them"
|
|
- "You know who you killed — avoid contradicting yourself"
|
|
|
|
### Strategy Injection (Toggleable):
|
|
- None: figure it out
|
|
- Basic: "Blend in, fake tasks, don't vent in front of others"
|
|
- Advanced: "Marinate teammate, frame third party, avoid double kills"
|
|
|
|
---
|
|
|
|
## Persona Persistence
|
|
|
|
### Storage:
|
|
Redis DB for each `{model}_{persona}` combo:
|
|
```json
|
|
{
|
|
"persona_id": "gpt4o_aggressive_leader",
|
|
"learned": {...},
|
|
"games_played": 42,
|
|
"win_rate": 0.65,
|
|
"impostor_win_rate": 0.70,
|
|
"crewmate_win_rate": 0.60,
|
|
"stats": {...}
|
|
}
|
|
```
|
|
|
|
### Separation:
|
|
- "GPT-4o as Aggressive Leader" ≠ "GPT-4o as Quiet Observer"
|
|
- Each persona builds own cross-game memory
|
|
- Learned strategies are persona-specific
|
|
|
|
---
|
|
|
|
## Strategy Injection Levels
|
|
|
|
Toggleable per persona:
|
|
|
|
| Level | Content |
|
|
|-------|---------|
|
|
| None | Just rules, figure it out |
|
|
| Basic | "Impostors vent, fake tasks, sabotage" |
|
|
| Intermediate | "Watch for inconsistent alibis, pair up" |
|
|
| Advanced | "Stack kills, marinate, third impostor framing" |
|
|
|
|
Different personas can have different injection levels to test learning vs. pre-trained strategies.
|