From c3aaddc824c7069454a77086fd87818ccc595232 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sun, 12 Apr 2026 19:23:03 +0800 Subject: [PATCH] fix(weixin): Stop auto-splitting messages by newlines; match Telegram behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The WeChat adapter was splitting every paragraph/line-break into a separate message, flooding users' chat interfaces. This behavior was unique to WeChat — the Telegram adapter keeps messages intact and only splits when exceeding the max length limit. Changes: - Simplify _split_delivery_units_for_weixin to return content as a single unit; splitting is now handled by length only (4000 chars). - Make _should_split_short_chat_block_for_weixin return False so that even short 2-6 line messages stay together by default. - Users who prefer per-line splitting can still enable it via WEIXIN_SPLIT_MULTILINE_MESSAGES=true. Discovered while building HermesClaw (a dual-proxy router for Hermes Agent + OpenClaw on the same WeChat account). Users consistently reported the newline-splitting behavior as a major UX pain point. Credit: Aaron Wong (@AaronWong1999, X: @AaronYonW) Co-authored-by: Qwen-Coder --- gateway/platforms/weixin.py | 57 +++++++++++-------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/gateway/platforms/weixin.py b/gateway/platforms/weixin.py index dc4e7cf969801..eb557b300879e 100644 --- a/gateway/platforms/weixin.py +++ b/gateway/platforms/weixin.py @@ -696,42 +696,14 @@ def _split_markdown_blocks(content: str) -> List[str]: def _split_delivery_units_for_weixin(content: str) -> List[str]: - """Split formatted content into chat-friendly delivery units. + """Return content as a single unit. - Weixin can render Markdown, but chat readability is better when top-level - line breaks become separate messages. Keep fenced code blocks intact and - attach indented continuation lines to the previous top-level line so - transformed tables/lists do not get torn apart. + Splitting is handled by ``_split_text_for_weixin_delivery`` based on + ``max_length`` only. Keeping messages intact (instead of splitting by + newlines) matches the behavior of the Telegram adapter and prevents + flooding the user's chat with many small messages. """ - units: List[str] = [] - - for block in _split_markdown_blocks(content): - if _FENCE_RE.match(block.splitlines()[0].strip()): - units.append(block) - continue - - current: List[str] = [] - for raw_line in block.splitlines(): - line = raw_line.rstrip() - if not line.strip(): - if current: - units.append("\n".join(current).strip()) - current = [] - continue - - is_continuation = bool(current) and raw_line.startswith((" ", "\t")) - if is_continuation: - current.append(line) - continue - - if current: - units.append("\n".join(current).strip()) - current = [line] - - if current: - units.append("\n".join(current).strip()) - - return [unit for unit in units if unit] + return [content] if content.strip() else [] def _looks_like_chatty_line_for_weixin(line: str) -> bool: @@ -761,13 +733,16 @@ def _looks_like_heading_line_for_weixin(line: str) -> bool: def _should_split_short_chat_block_for_weixin(block: str) -> bool: - """Split only chat-like multiline blocks into separate bubbles.""" - lines = [line for line in block.splitlines() if line.strip()] - if not 2 <= len(lines) <= 6: - return False - if _looks_like_heading_line_for_weixin(lines[0]): - return False - return all(_looks_like_chatty_line_for_weixin(line) for line in lines) + """Return False to keep short chat messages as a single unit. + + Splitting short chat-like blocks into separate bubbles was originally + intended to create a more natural feel, but in practice it floods the + user's WeChat with many small messages. Returning ``False`` keeps + the default compact behavior consistent with Telegram and other platforms. + Users who prefer per-line splitting can still enable it via + ``WEIXIN_SPLIT_MULTILINE_MESSAGES=true``. + """ + return False def _pack_markdown_blocks_for_weixin(content: str, max_length: int) -> List[str]: