fix(telegram): move fenced-code-block splitting into Telegram-specific helper

Move the fenced-code-block-aware splitting logic out of the shared
split_message helper (used by Signal, Slack, Discord, Weixin, etc.)
and into a Telegram-specific _split_telegram_markdown function.

The shared split_message remains a plain-text chunker. The Telegram
channel now uses _split_telegram_markdown for its raw Markdown paths
that feed _markdown_to_telegram_html, preventing broken HTML rendering
when splits fall inside fenced code blocks.

Also fixes a regression where content beginning with whitespace before
a fence could emit a whitespace-only chunk.

Addresses review feedback on #4257.
This commit is contained in:
axelray-dev
2026-06-11 13:52:19 +08:00
committed by Xubin Ren
parent 131446fa61
commit a5a816abaf
4 changed files with 138 additions and 101 deletions
-46
View File
@@ -368,22 +368,6 @@ def maybe_persist_tool_result(
)
def _fence_line(content: str, fence_pos: int) -> str:
line_end = content.find("\n", fence_pos)
if line_end < 0:
return content[fence_pos:]
return content[fence_pos:line_end]
def _split_inside_fenced_code_block(content: str, pos: int) -> tuple[bool, int, str]:
if content[:pos].count("```") % 2 == 0:
return False, -1, ""
opening = content.rfind("```", 0, pos)
if opening < 0:
return True, -1, "```"
return True, opening, _fence_line(content, opening)
def split_message(content: str, max_len: int = 2000) -> list[str]:
"""
Split content into chunks within max_len, preferring line breaks.
@@ -411,36 +395,6 @@ def split_message(content: str, max_len: int = 2000) -> list[str]:
pos = cut.rfind(" ")
if pos <= 0:
pos = max_len
inside_code, opening, fence = _split_inside_fenced_code_block(content, pos)
if inside_code:
if opening > 0:
pos = opening
else:
closing = "\n```"
min_code_pos = len(fence)
if content.startswith(fence + "\n"):
min_code_pos += 1
if pos < min_code_pos and min_code_pos + len(closing) > max_len:
chunks.append(content[:max_len])
content = content[max_len:].lstrip()
continue
if pos + len(closing) > max_len:
budget = max_len - len(closing)
if budget > 0:
recut = content[:budget]
adjusted = recut.rfind("\n")
if adjusted <= 0:
adjusted = recut.rfind(" ")
pos = adjusted if adjusted > 0 else budget
else:
closing = "```"
pos = max_len - len(closing)
chunks.append(content[:pos] + closing)
remainder = content[pos:]
if remainder.startswith("\n"):
remainder = remainder[1:]
content = f"{fence}\n{remainder}"
continue
chunks.append(content[:pos])
content = content[pos:].lstrip()
return chunks