{"record":{"id":"84783ae774d21fe2","repo":"FoundationAgents/MetaGPT","slug":"moderator-s-instructions-must-include-save-or-pois","errorCode":null,"errorMessage":"Moderator's instructions must include save or poison keyword","messagePattern":"Moderator's instructions must include save or poison keyword","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"metagpt/ext/werewolf/roles/witch.py","lineNumber":28,"sourceCode":"    special_action_names: list[str] = [\"Save\", \"Poison\"]\n\n    async def _think(self):\n        \"\"\"女巫涉及两个特殊技能，因此在此需要改写_think进行路由\"\"\"\n        news = self.rc.news[0]\n        assert news.cause_by == any_to_str(InstructSpeak)  # 消息为来自Moderator的指令时，才去做动作\n        if not news.restricted_to:\n            # 消息接收范围为全体角色的，做公开发言（发表投票观点也算发言）\n            self.rc.todo = Speak()\n        elif self.profile in news.restricted_to:\n            # FIXME: hard code to split, restricted为\"Moderator\"或\"Moderator,角色profile\"\n            # Moderator加密发给自己的，意味着要执行角色的特殊动作\n            # 这里用关键词进行动作的选择，需要Moderator侧的指令进行配合\n            if \"save\" in news.content.lower():\n                self.rc.todo = Save()\n            elif \"poison\" in news.content.lower():\n                self.rc.todo = Poison()\n            else:\n                raise ValueError(\"Moderator's instructions must include save or poison keyword\")\n        return True\n","sourceCodeStart":10,"sourceCodeEnd":30,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/ext/werewolf/roles/witch.py#L10-L30","documentation":"In the werewolf (Wolf) game, the Witch role decides its action by keyword-matching the Moderator's encrypted instruction: content containing 'save' selects Save(), 'poison' selects Poison(). If the restricted message from the Moderator contains neither keyword (case-insensitive), this ValueError is raised. The design is a documented FIXME: it depends on the Moderator's prompt wording.","triggerScenarios":"The Moderator sends a Witch-targeted restricted message whose content lacks the substrings 'save' or 'poison' — e.g. localized/translated prompts, reworded moderator instructions, or words like 'rescue'/'venom'.","commonSituations":"Customizing werewolf prompts (especially translating to non-English) without keeping the English keywords; upgrading MetaGPT where moderator prompt wording drifted; messages that merely mention the words in an unrelated form.","solutions":["Keep the literal English keywords 'save' or 'poison' in any customized Moderator instruction aimed at the Witch.","If localizing, add the localized keywords to the branch checks or match on both.","As a defensive patch, default to a no-op (e.g. Speak()) instead of raising when no keyword matches."],"exampleFix":"# before\nif \"save\" in news.content.lower():\n    self.rc.todo = Save()\nelif \"poison\" in news.content.lower():\n    self.rc.todo = Poison()\nelse:\n    raise ValueError(\"Moderator's instructions must include save or poison keyword\")\n\n# after (also accept localized keywords, no raise)\ncontent = news.content.lower()\nif \"save\" in content or \"救人\" in content:\n    self.rc.todo = Save()\nelif \"poison\" in content or \"毒\" in content:\n    self.rc.todo = Poison()\nelse:\n    self.rc.todo = Speak()","handlingStrategy":"validation","validationCode":"def witch_action_from(content: str):\n    c = content.lower()\n    if \"save\" in c:\n        return Save()\n    if \"poison\" in c:\n        return Poison()\n    return None  # caller decides default instead of crashing","typeGuard":null,"tryCatchPattern":"try:\n    await witch.handle(msg)\nexcept ValueError as e:\n    if \"save or poison keyword\" in str(e):\n        logger.warning(\"moderator instruction lacked witch keyword: %s\", msg.content)\n        return  # tolerate and continue the game\n    raise","preventionTips":["Treat moderator prompts as a contract: keep English keywords in all localizations.","Test custom werewolf prompts against the witch keyword branches."],"tags":["werewolf","prompt-contract","keyword-matching","game"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}