fix(telegram): hard-cut fence splits when the closer cannot fit

Adaptive HTML limits can shrink max_len to the fence prefix size. Treat
budget <= min_code_pos as a hard cut so the splitter still advances.
This commit is contained in:
santhreal 2026-07-22 22:59:25 -07:00 committed by chengyongru
parent 017a4946e2
commit 98d661775e
2 changed files with 36 additions and 10 deletions

View File

@ -93,7 +93,7 @@ def _split_telegram_markdown(content: str, max_len: int) -> list[str]:
# When the only break in range is the opening fence newline, # When the only break in range is the opening fence newline,
# cutting there re-emits the same fence and never advances. # cutting there re-emits the same fence and never advances.
if pos < min_code_pos: if pos < min_code_pos:
if min_code_pos + len(closing) > max_len: if min_code_pos + len(closing) >= max_len:
chunks.append(content[:max_len]) chunks.append(content[:max_len])
content = content[max_len:].lstrip() content = content[max_len:].lstrip()
continue continue
@ -105,15 +105,15 @@ def _split_telegram_markdown(content: str, max_len: int) -> list[str]:
pos = adjusted if adjusted >= min_code_pos else budget pos = adjusted if adjusted >= min_code_pos else budget
elif pos + len(closing) > max_len: elif pos + len(closing) > max_len:
budget = max_len - len(closing) budget = max_len - len(closing)
if budget > 0: if budget <= min_code_pos:
recut = content[:budget] chunks.append(content[:max_len])
adjusted = recut.rfind("\n", min_code_pos) content = content[max_len:].lstrip()
if adjusted < min_code_pos: continue
adjusted = recut.rfind(" ", min_code_pos) recut = content[:budget]
pos = adjusted if adjusted >= min_code_pos else budget adjusted = recut.rfind("\n", min_code_pos)
else: if adjusted < min_code_pos:
closing = "```" adjusted = recut.rfind(" ", min_code_pos)
pos = max_len - len(closing) pos = adjusted if adjusted >= min_code_pos else budget
chunks.append(content[:pos] + closing) chunks.append(content[:pos] + closing)
remainder = content[pos:] remainder = content[pos:]
if remainder.startswith("\n"): if remainder.startswith("\n"):

View File

@ -268,6 +268,32 @@ def test_split_telegram_markdown_long_single_line_code_body() -> None:
_assert_code_blocks_render_balanced(chunks) _assert_code_blocks_render_balanced(chunks)
def test_split_telegram_markdown_tiny_limit_hard_cuts_fence_prefix() -> None:
"""Adaptive HTML limits can shrink max_len to the fence+closer size."""
body = "a" * 100
content = f"```\n{body}"
chunks = _split_telegram_markdown(content, max_len=8)
assert chunks
assert all(len(chunk) <= 8 for chunk in chunks)
assert "".join(chunks).replace("```", "").replace("\n", "") == body
def test_split_telegram_markdown_tiny_limit_with_early_body_newline() -> None:
body = "a" * 100
content = f"```\na\n{body}"
chunks = _split_telegram_markdown(content, max_len=8)
assert chunks
assert all(len(chunk) <= 8 for chunk in chunks)
plain = "".join(chunks).replace("```", "")
assert "a" in plain
assert plain.count("a") >= 100
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_start_creates_separate_pools_with_proxy(monkeypatch) -> None: async def test_start_creates_separate_pools_with_proxy(monkeypatch) -> None:
_FakeHTTPXRequest.clear() _FakeHTTPXRequest.clear()