import re from typing import Dict, Optional from agent_build_sdk.model.werewolf_model import ( AgentReq, STATUS_DAY, STATUS_HUNTER, STATUS_HUNTER_RESULT, STATUS_NIGHT, STATUS_NIGHT_INFO, STATUS_RESULT, STATUS_SHERIFF_ELECTION, STATUS_SHERIFF_PK, STATUS_SHERIFF_SPEECH, STATUS_SHERIFF_SPEECH_ORDER, STATUS_SHERIFF_VOTE, STATUS_SKILL_RESULT, STATUS_VOTE, STATUS_VOTE_RESULT, STATUS_SHERIFF, ) from core import ruleset def _extract_sheriff_from_text(text: str) -> Optional[str]: s = (text or "").strip() if not s: return None if ruleset.SHERIFF_TEAR in s: return None patterns = [ r"警徽归属[::]?\s*([^\s,,。;;]+)", r"警徽(?:移交|交给|传递|传给|给)[::]?\s*([^\s,,。;;]+)", r"移交(?:警徽)?给[::]?\s*([^\s,,。;;]+)", r"警长[::]\s*([^\s,,。;;]+)", ] matches: list[tuple[int, str]] = [] for pat in patterns: for m in re.finditer(pat, s): matches.append((m.start(), (m.group(1) or "").strip())) if not matches: return None _, name = sorted(matches, key=lambda x: x[0])[-1] name = name.strip().strip("[]【】()()\"'“”‘’`").strip(",,。;;::") if not name or name == ruleset.SHERIFF_TEAR: return None return name def parse_event(req: AgentReq) -> Dict[str, str]: return { "status": req.status or "", "name": req.name or "", "message": req.message or "", "round": str(req.round) if req.round is not None else "", "role": req.role or "", } def event_to_fact(req: AgentReq) -> Optional[Dict[str, str]]: status = req.status or "" round_no = str(req.round) if req.round is not None else "" if status == STATUS_VOTE: return { "type": "vote", "round": round_no, "voter": req.name or "", "target": req.message or "", } if status == STATUS_VOTE_RESULT: return { "type": "vote_result", "round": round_no, "out": (req.name or req.message or ""), } if status == STATUS_NIGHT_INFO: return { "type": "night_info", "round": round_no, "message": req.message or "", } if status == STATUS_NIGHT: return { "type": "night", "round": round_no, "message": req.message or "", } if status == STATUS_DAY: return { "type": "day", "round": round_no, "message": req.message or "", } if status == STATUS_SKILL_RESULT: return { "type": "skill_result", "round": round_no, "name": req.name or "", "message": req.message or "", } if status == STATUS_HUNTER: return { "type": "hunter", "round": round_no, "name": req.name or "", "message": req.message or "", } if status == STATUS_HUNTER_RESULT: return { "type": "hunter_result", "round": round_no, "name": req.name or "", "target": req.message or "", } if status == STATUS_RESULT: return { "type": "result", "round": round_no, "message": req.message or "", } if status == STATUS_SHERIFF_ELECTION: return { "type": "sheriff_election", "round": round_no, "message": req.message or "", } if status == STATUS_SHERIFF_SPEECH: return { "type": "sheriff_speech", "round": round_no, "name": req.name or "", "message": req.message or "", } if status == STATUS_SHERIFF_PK: return { "type": "sheriff_pk", "round": round_no, "name": req.name or "", "message": req.message or "", } if status == STATUS_SHERIFF_VOTE: return { "type": "sheriff_vote", "round": round_no, "name": req.name or "", "target": req.message or "", } if status == STATUS_SHERIFF_SPEECH_ORDER: return { "type": "sheriff_speech_order", "round": round_no, "message": req.message or "", } if status == STATUS_SHERIFF: sheriff_name = req.name or _extract_sheriff_from_text(req.message or "") if not sheriff_name: return None return { "type": "sheriff", "round": round_no, "name": sheriff_name, } return None