from __future__ import annotations import re _CONTROL_CHAR_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]") _MULTI_NEWLINE_RE = re.compile(r"\n{3,}") _LENGTH_PREFIX_RE = re.compile(r"^(\d+)\n") _TERMINAL_ESCAPE_RE = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]") _MAX_TERMINAL_MSG_LEN = 200 def sanitize_terminal_text(text: str, max_len: int = _MAX_TERMINAL_MSG_LEN) -> str: """净化终端输出文本,移除 ANSI 转义序列和控制字符。 用于日志记录和错误消息净化。 """ if not text: return "" text = _TERMINAL_ESCAPE_RE.sub("", text) text = _CONTROL_CHAR_RE.sub("", text) if len(text) > max_len: text = text[:max_len] + "..." return text def sanitize_outbound_text(text: str) -> str: """净化出站文本,移除 iMessage 中不支持的格式。 - 去除 \\r 字符(换行标准化) - 去除长度前缀损坏(如 "42\\nThis is message") - 过滤控制字符 - 合并多余空白行 """ text = text.replace("\r", "") text = _strip_length_prefix(text) text = _CONTROL_CHAR_RE.sub("", text) text = _MULTI_NEWLINE_RE.sub("\n\n", text) text = text.strip() return text def _strip_length_prefix(text: str) -> str: match = _LENGTH_PREFIX_RE.match(text) if match: prefix_len = int(match.group(1)) remaining = text[match.end() :] if abs(len(remaining) - prefix_len) <= 5: return remaining return text def media_placeholder(media_type: str) -> str: """为纯媒体消息生成占位文本。 OpenClaw 在无文本媒体消息中生成 等占位符。 """ placeholders = { "image": "", "video": "", "audio": "", "file": "", } return placeholders.get(media_type, "")