"""Enforce user-specified delegate role on Lead projects (override docs→content drift).""" from __future__ import annotations import logging import re from typing import TYPE_CHECKING from butler.utilities.env_parse import env_truthy if TYPE_CHECKING: from butler.tools.delegate_phases import DelegateRunState logger = logging.getLogger(__name__) _DEV_SIGNALS: tuple[re.Pattern[str], ...] = ( re.compile(r"role\s*[=:]\s*dev\b", re.I), re.compile(r"委派\s*开发", re.I), re.compile(r"开发代理", re.I), re.compile(r"交给\s*开发", re.I), re.compile(r"禁止(用|使用)?\s*content", re.I), re.compile(r"不要(用|使用)?\s*content", re.I), re.compile(r"禁止\s*内容代理", re.I), ) _CONTENT_SIGNALS: tuple[re.Pattern[str], ...] = ( re.compile(r"role\s*[=:]\s*content\b", re.I), re.compile(r"委派\s*内容", re.I), re.compile(r"内容代理", re.I), re.compile(r"交给\s*content", re.I), re.compile(r"禁止(用|使用)?\s*dev\b", re.I), re.compile(r"不要(用|使用)?\s*dev\b", re.I), re.compile(r"禁止\s*开发代理", re.I), ) _FORBID_DELEGATE_SIGNALS: tuple[re.Pattern[str], ...] = ( re.compile(r"不要委派", re.I), re.compile(r"禁止委派", re.I), re.compile(r"不(要|许)委派", re.I), re.compile(r"不要\s*delegate", re.I), re.compile(r"勿\s*委派", re.I), ) _READONLY_ONLY_SIGNALS: tuple[re.Pattern[str], ...] = ( re.compile(r"只读", re.I), re.compile(r"仅查看", re.I), re.compile(r"不要改", re.I), re.compile(r"不要修改", re.I), re.compile(r"勿改", re.I), re.compile(r"read[\s-]?only", re.I), ) _DELEGATE_INTENT_SIGNALS: tuple[re.Pattern[str], ...] = ( re.compile(r"委派", re.I), re.compile(r"delegate", re.I), re.compile(r"交给\s*(开发|内容|review|审查)?\s*代理", re.I), re.compile(r"开发代理", re.I), re.compile(r"内容代理", re.I), ) _LEAD_SELF_READ_FILE = re.compile( r"(自己|请你|请你先|本线程).{0,12}read_file|read_file.{0,40}(后|然后)", re.I, ) def _normalize_role(role: str) -> str: return str(role or "").replace("_agent", "").strip().lower() def _user_query_head(text: str) -> str: """Parse only the user-facing lines; ignore trailing Skill/Memory injections.""" raw = str(text or "").strip() if not raw: return "" for marker in ( "## 相关知识", "## Related knowledge", "### `", "