from __future__ import annotations from dataclasses import dataclass ReplyToMode = str REPLY_OFF: ReplyToMode = "off" REPLY_FIRST: ReplyToMode = "first" REPLY_ALL: ReplyToMode = "all" REPLY_BATCHED: ReplyToMode = "batched" REPLY_MODES = frozenset({REPLY_OFF, REPLY_FIRST, REPLY_ALL, REPLY_BATCHED}) @dataclass class ReplyConfig: mode: ReplyToMode = REPLY_OFF thread_only: bool = False @classmethod def from_config(cls, config: dict) -> ReplyConfig: mode = config.get("reply_to_mode", REPLY_OFF) if mode not in REPLY_MODES: mode = REPLY_OFF thread_only = bool(config.get("reply_thread_only", False)) return cls(mode=mode, thread_only=thread_only) class ReplyManager: def __init__(self, config: dict | None = None): self._config = ReplyConfig.from_config(config or {}) @property def mode(self) -> ReplyToMode: return self._config.mode @property def thread_only(self) -> bool: return self._config.thread_only def reload_config(self, key: str, value) -> None: from dataclasses import replace if key == "reply_to_mode" and value in REPLY_MODES: self._config = replace(self._config, mode=value) def should_reply(self, chat_type: str, has_thread: bool = False) -> bool: if chat_type == "direct": return False mode = self._config.mode if mode == REPLY_OFF: return False if mode == REPLY_FIRST and chat_type == "direct": return True if mode == REPLY_ALL: return True if mode == REPLY_BATCHED: return True return False def resolve_reply_target(self, chat_id: str, root_id: str | None) -> str | None: """返回应该回复到的消息 ID(用作 root_id),None 表示不绑定线程。""" if self._config.mode == REPLY_OFF: return None if self._config.thread_only and root_id: return root_id if self._config.mode in (REPLY_ALL, REPLY_BATCHED) and root_id: return root_id return None