AutoWerewolf is a system where multiple LLM-driven agents play the Werewolf game against each other under a neutral moderator. The system must:
- Implement full 12-player Werewolf rules (aligned with
werewolf_rules_en.md). - Support multiple model backends: HTTP API models and local Ollama models.
- Use LangChain as the orchestration framework for all agent logic and tools.
- Be robust and extensible as an engineering project (not a one-off script).
The initial scope focuses on self-play (all players are LLM agents) with a human able to observe logs and optionally join as a player later.
-
Game Orchestrator
- Owns the lifecycle of a single game instance.
- Enforces rules and turn order (night/day cycle, voting, deaths, win conditions).
- Interfaces with the Moderator agent to turn game state into natural-language prompts for players.
-
Moderator Agent (LLM-backed)
- Neutral narrator and rule enforcer in natural language.
- Explains state transitions, announces deaths, manages speaking order textually.
- Implemented as a LangChain chain/tool that converts internal state → player-facing messages.
-
Player Agents (LLM-backed)
- 12 agents: 4 Werewolves, 4 Villagers, 4 special roles (Seer, Witch, Hunter, Guard / Idiot).
- Each agent has:
- A hidden role and team alignment.
- Memory of past days/nights, speeches, votes, checks, etc.
- A LangChain chain that consumes structured game events and outputs actions (speech, vote, night action).
-
Game Engine / Rules Layer
- Purely deterministic, non-LLM logic implementing:
- Role assignment and validation.
- Night action ordering and conflict resolution (Seer → Wolves → Witch → Guard/Hunter, etc.).
- Sheriff election and badge passing/tearing.
- Win condition evaluation (Side-Elimination / Tu Bian by default).
- Exposed through a clear API callable by the Orchestrator.
- Purely deterministic, non-LLM logic implementing:
-
Model Backend Abstraction Layer
- Wraps different LLM providers behind a common interface:
- HTTP API models (e.g., OpenAI-compatible APIs, custom inference servers).
- Ollama local models.
- Provides LangChain-compatible
LLM/ChatModelimplementations and configuration.
- Wraps different LLM providers behind a common interface:
-
Persistence and Logging
- Structured logs for each game:
- Game config (seed, models used, role distribution).
- Turn-by-turn events, prompts, responses, and actions.
- Optional storage backends: local JSON/SQLite initially.
- Structured logs for each game:
-
CLI / Runner
- Entry point to launch games, choose models, seeds, and observe game progress.
- Future: simple web UI can build on the same Orchestrator API.
-
Game Setup
- Validate configuration (number of players, role set A/B, models, seeds).
- Initialize Model Backends and LangChain LLM instances.
- Create Player agents and the Moderator agent.
- Randomly assign roles and initial sheriff election flag.
-
Night/Day Cycle
- Loop until a win condition is met.
- Night:
- Orchestrator requests night actions from relevant Player agents via their LangChain chains.
- Engine resolves actions (kills, saves, protections, checks, shots) according to rules.
- Day:
- On Day 1, run sheriff election.
- Announce deaths; collect last words.
- Manage discussion rounds (speeches) for all alive players.
- Collect votes, lynch target, resolve last words and potential Hunter shot.
-
Game End
- Engine checks win conditions (Village vs Werewolves).
- Moderator announces results and optionally summarizes key events.
- Logs are written and finalized.
-
Playerid: strname: strrole: Rolealignment: Alignment(Werewolf / Good)is_alive: boolis_sheriff: boolagent: PlayerAgent(LangChain-based)
-
Role(enum)WEREWOLFVILLAGERSEERWITCHHUNTERGUARDVILLAGE_IDIOT
-
GameConfignum_players: int(default 12)role_set: Literal["A", "B"](A: Guard, B: Village Idiot)model_config: ModelConfig(per-role or global)random_seed: Optional[int]rule_variants: RuleVariants(e.g. witch_self_heal_first_night, side_elimination=true)
-
GameStateday_number: intphase: Literal["NIGHT", "DAY"]players: list[Player]sheriff_id: Optional[str]badge_torn: boolnight_events: list[Event]day_events: list[Event]history: list[Event]
-
Event- Timestamped structured events (e.g.,
NightKill,SeerCheck,WitchSave,VoteCast,SheriffElection,HunterShot,VillageIdiotReveal).
- Timestamped structured events (e.g.,
-
Action- Agent-chosen operations:
SelectKillTarget,SelectVoteTarget,MakeSpeech,UsePotion,GuardTarget,SheriffDecision,SelfExplode, etc.
- Agent-chosen operations:
RuleVariants encapsulates toggles that might differ by playgroup but should be configurable:
witch_can_self_heal_n1: boolguard_can_self_guard: boolsame_guard_same_save_kills: bool(true if double-protected still dies)win_mode: Literal["SIDE_ELIMINATION", "CITY_ELIMINATION"]allow_wolf_self_explode: boolallow_wolf_self_knife: bool
The Game Engine reads these flags but Player Agents are told about the configured rules through system prompts.
- All agents are implemented as LangChain chains with:
- A system prompt describing rules, objectives, and constraints.
- Input: a structured description of the current game state from that agent's perspective.
- Output: a constrained JSON (or other schema) representing
Actionor aSpeech.
- Use LangChain Structured Output (e.g.
PydanticOutputParserorwith_structured_output) to ensure actions are machine-readable. - Use LangChain Memory to provide short-term conversational context per agent:
ConversationBufferMemoryorConversationSummaryMemoryscoped to each player.- Additional custom memory that stores structured facts (e.g., "Player 3 claimed Seer on Day 1").
- Input:
- The full
GameState(or a filtered view) and a list ofEventobjects for the last transition.
- The full
- Output:
- Natural language narration for logs and for players (e.g., "Last night, Player 5 died.").
- Responsibilities:
- Convert machine state transitions into consistent human-readable descriptions.
- Optionally, generate short commentary/summary for observers.
Implementation sketch (Python):
ModeratorChain(LangChain Runnable) wraps aChatModelwith a system prompt:- Explain that it must never leak hidden information.
- It receives the game history and the audience ("to all players", "to werewolves only", etc.).
Each role has a dedicated chain or a shared base chain with role-specific system prompts:
-
Inputs:
role: seer/wolf/etc. (fixed in system prompt).phase:NIGHTorDAY.visible_events: only those this player should know (public speeches, own role, own prior actions, seer results, etc.).action_type: e.g.,"NIGHT_ACTION","SPEECH","VOTE".candidate_targets: valid player IDs (alive, not self when forbidden, etc.).
-
Outputs:
- For speech:
{ "type": "speech", "content": "..." }. - For vote:
{ "type": "vote", "target_player_id": "P03" }. - For night action: role-specific fields such as
seer_target_id,wolf_kill_target_id,witch_decision,guard_target_id.
- For speech:
-
Special Role Logic (encoded via prompts + engine verification):
- Seer: chooses one player each night to check.
- Witch: chooses to use cure/poison, respecting once-per-game limit and cannot use both in one night.
- Hunter: chooses a target to shoot when allowed.
- Guard: chooses a protection target; engine blocks illegal repeats.
- Village Idiot: decides whether to reveal when lynched (or this may be automated by rule).
The Game Engine must validate outputs and, on invalid responses, either re-prompt or fall back to random valid actions (with logging).
- Support at least two categories of models:
- HTTP API models (e.g.
openai,azure, or custom/chat/completionsendpoints). - Ollama local models (e.g.
llama3,qwen, etc.).
- HTTP API models (e.g.
- Make backends configurable via a single
ModelConfigthat the orchestrator reads.
Example structure:
ModelConfigbackend: Literal["api", "ollama"]model_name: strapi_base: Optional[str](for HTTP APIs)api_key: Optional[str]temperature: floatmax_tokens: inttimeout_s: int
Support per-role overrides:
AgentModelConfigdefault: ModelConfigmoderator: Optional[ModelConfig]werewolf: Optional[ModelConfig]villager: Optional[ModelConfig]seer: Optional[ModelConfig]witch: Optional[ModelConfig]hunter: Optional[ModelConfig]guard: Optional[ModelConfig]village_idiot: Optional[ModelConfig]
Implement a small adapter that returns a LangChain ChatModel given a ModelConfig:
- For
backend == "api":- Use
ChatOpenAIorChatAnthropic-style wrappers depending on chosen provider, or a genericChatOpenAIwith customopenai_api_base.
- Use
- For
backend == "ollama":- Use
ChatOllamafromlangchain-ollama.
- Use
Exposed function:
get_chat_model(config: ModelConfig) -> BaseChatModel
The Orchestrator uses this to construct all agent chains.
- Own the main event loop:
- Initialize game from
GameConfig. - For each phase, call the Game Engine to determine legal actions and next required decisions.
- Call Player agents (LangChain chains) to obtain decisions.
- Commit decisions in the engine and produce new
Events. - Call Moderator to produce human-readable messages.
- Initialize game from
- Guarantee no information leaks:
- Each agent gets only its permitted view of
GameState. - Moderator messages are filtered for audience.
- Each agent gets only its permitted view of
-
Provide a deterministic API like:
apply_night_actions(game_state, night_actions) -> game_state, eventsapply_day_speeches(game_state, speeches) -> eventsapply_votes(game_state, votes) -> game_state, eventscheck_win_condition(game_state) -> Optional[WinningTeam]
-
Handle rule ordering:
- Night order aligned with
werewolf_rules_en.md:- Werewolves choose kill target.
- Seer checks a player (or configured order per group).
- Witch receives info on kill target; decides cure/poison.
- Guard protects a target.
- Hunter/Village Idiot passive triggers later on death.
- Night order aligned with
-
Implement sheriff logic:
- On Day 1, run special
SheriffElectionphase. - Sheriff has 1.5 votes and speaks first/last per rules.
- On sheriff death, apply badge pass/tear decision.
- On Day 1, run special
For each night:
- Collect Werewolf Decision
- Visible info: all public history + werewolf camp private chat (if enabled).
- Chain:
wolf_night_chainreturnskill_target_idorself_explode/self_knifedecisions.
- Collect Seer Check
seer_chainsuggests atarget_idto inspect.- Engine resolves alignment and stores in Seer private memory.
- Witch Decision
witch_chainreceives info about who was attacked, remaining potions, and public state.- Returns
use_cure: bool,use_poison: bool, and possiblepoison_target_id.
- Guard Protection (if using Set A)
guard_chainchoosesguard_target_idwith engine enforcing constraints.
- Resolve Night
- Engine applies rules (attacks, saves, protections, conflicts like
same_guard_same_save_kills). - Generates
NightKill,Saved, andCheckResultevents.
- Engine applies rules (attacks, saves, protections, conflicts like
For each day:
- Sheriff Election (Day 1)
- Orchestrator asks each agent if they want to run.
- Candidates give speeches; others vote; Engine computes sheriff.
- Announce Deaths and Last Words
- Moderator chain narrates results.
- Orchestrator solicits last words speeches where allowed (night-kill first night, all lynched players).
- Discussion Round
- Orchestrator iterates over alive players (according to sheriff ordering) and prompts
day_speech_chainfor each.
- Orchestrator iterates over alive players (according to sheriff ordering) and prompts
- Voting
- All alive players provide a vote target.
- Engine tallies votes, applying sheriff 1.5x multiplier, resolves ties per config.
- Lynch Resolution
- Apply death and triggers:
- Hunter shot if conditions met.
- Village Idiot reveal and survival if lynched.
- Add events to history.
- Apply death and triggers:
- Check Win Condition
- If a team has won, exit loop; otherwise proceed to next night.
- Seed all randomness (role assignment, tie-breaking, fallback random actions) with a known
random_seed. - Log prompts and responses to enable replay and debugging.
- Provide an option to run in deterministic mode with fixed temperature and seeds.
- Structured output validation:
- If an agent returns invalid JSON or illegal actions, re-prompt once with explicit error message.
- If still invalid, choose a random legal action and log the issue.
- Timeouts and retries:
- Configurable per-model timeout; on timeout, retry N times or fallback to default action.
- Support running at fast simulation speed by:
- Skipping verbose natural-language narration when not needed; use compact logs.
- Using small, fast models via Ollama or API.
- Clean separation between:
- Rule logic (pure Python, unit-testable).
- Agent chains (LangChain graph; swap models or prompts freely).
- Backends (API vs Ollama configurable without code changes).
autowerewolf/
docs/
werewolf_rules_en.md
werewolf_rules.md
system_design_en.md # this file
autowerewolf/
__init__.py
config/
__init__.py
models.py # ModelConfig, AgentModelConfig, RuleVariants, GameConfig
engine/
__init__.py
roles.py # enums and role definitions
state.py # GameState, Player, Event, Action models
rules.py # core resolution logic, win conditions
agents/
__init__.py
backend.py # get_chat_model, backend selection (api/ollama)
moderator.py # ModeratorChain implementation
player_base.py # BasePlayerAgent (LangChain chain wrapper)
roles/
seer.py
werewolf.py
villager.py
witch.py
hunter.py
guard.py
village_idiot.py
orchestrator/
__init__.py
game_orchestrator.py # main game loop
io/
__init__.py
logging.py # JSON + human-readable logging utilities
persistence.py # save/load game logs
cli/
__init__.py
main.py # CLI entry (e.g. `python -m autowerewolf.cli.main`)
pyproject.toml or requirements.txt
README.md
- Use a recent LangChain release compatible with:
langchain-corelangchain-communitylangchain-ollama
- Patterns:
- Define each agent as a
Runnablechain created viachat_model | parserorChatPromptTemplate | chat_model | parser. - Use
RunnableSequenceorLCELcomposition for more complex flows.
- Define each agent as a
-
Unit Tests (no LLMs):
- Rules engine (
rules.py) for all night/day interactions and edge cases. - Win condition checks.
- Sheriff election and badge pass/tear.
- Rules engine (
-
Integration Tests (with mocked LLMs):
- Replace all agents with deterministic stubs that return fixed actions.
- Simulate full games to ensure orchestrator and engine interactions are correct.
-
Smoke Tests (with real models):
- Run short games with small models (Ollama) to verify:
- No crashes.
- Actions are valid most of the time.
- Logs are complete.
- Run short games with small models (Ollama) to verify:
-
Local Development:
- Install via
pip(editable mode) and run CLI. - For Ollama backend, require
ollamainstalled and a model pulled.
- Install via
-
Configuration Files:
- YAML/JSON config for
GameConfigandAgentModelConfig. - Allow overriding via CLI flags (backend, model_name, seed, etc.).
- YAML/JSON config for
-
Future Extensions:
- Web dashboard for observing games in real time.
- Support human players.
- Additional role sets and custom rule variants.