feat(engine): add faction power system with event triggers

- Add FactionData model with power and members fields
- Add FactionEventResult model for faction event responses
- Add faction field to AgentState
- Implement faction classification based on emotion
- Add faction event triggers (festival/panic) when power >= 5
- Update StepResponse to include triggered_faction_event
- Add tests for new faction system

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2025-12-30 12:01:07 +08:00
parent 012956f817
commit 1fd318c9e3
6 changed files with 181 additions and 27 deletions

View File

@@ -306,16 +306,45 @@ def test_factions_exists_in_world_state(client):
factions = data["world_state"]["factions"]
assert "optimists" in factions
assert "fearful" in factions
assert "neutral" in factions
# 验证新结构:每个派系包含 power 和 members
assert "power" in factions["optimists"]
assert "members" in factions["optimists"]
assert "power" in factions["fearful"]
assert "members" in factions["fearful"]
def test_factions_count_matches_agents(client):
"""测试派系总数等于 agent 数量"""
"""测试派系成员总数等于非中立 agent 数量"""
resp = client.post("/step", json={"events": []})
data = resp.json()
factions = data["world_state"]["factions"]
total = factions["optimists"] + factions["fearful"] + factions["neutral"]
agent_count = len(data["world_state"]["agents"])
# 新结构:统计 members 列表长度
total_in_factions = (
len(factions["optimists"]["members"]) +
len(factions["fearful"]["members"])
)
# 中立 agent 不在任何派系中
# 验证 power 等于 members 数量
assert factions["optimists"]["power"] == len(factions["optimists"]["members"])
assert factions["fearful"]["power"] == len(factions["fearful"]["members"])
assert total == agent_count
def test_agent_has_faction_field(client):
"""测试 agent 包含 faction 字段"""
resp = client.post("/step", json={"events": []})
data = resp.json()
for agent_id, agent in data["world_state"]["agents"].items():
assert "faction" in agent
assert agent["faction"] in ["optimists", "fearful", "neutral"]
def test_triggered_faction_event_in_response(client):
"""测试响应包含 triggered_faction_event 字段"""
resp = client.post("/step", json={"events": []})
data = resp.json()
assert "triggered_faction_event" in data
assert "type" in data["triggered_faction_event"]
assert "source_faction" in data["triggered_faction_event"]