mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-28 18:19:28 +00:00
fix(gateway): balance code fences on every remaining chunk-split path
Widen #48476's fence guarantees to the two splitters that still emitted fence-broken chunks: * GatewayStreamConsumer._split_text_chunks (fallback final send): close the orphaned ``` at each chunk boundary and reopen it — with the original language tag — on the next chunk, mirroring BasePlatformAdapter.truncate_message's contract. Headroom is reserved so balanced chunks stay within the platform limit. * Slack block_kit._split_text (3000-char section chunking): same close/reopen balancing for mrkdwn section text carrying fences. With these, every chunk boundary — non-streaming send (truncate_message), streaming overflow (_truncate_for_stream via adapter.truncate_message per #45938), fallback final (_split_text_chunks), final-send balance (ensure_closed_code_fences), and Block Kit section splits — delivers fence-balanced chunks. Regression tests probe each path with fenced fixtures, assert per-chunk balance, limit compliance, language-tag reopening, and prose passthrough.
This commit is contained in:
parent
c934c533db
commit
eaa35ae68f
4 changed files with 176 additions and 8 deletions
|
|
@ -536,19 +536,40 @@ def render_blocks(
|
|||
|
||||
|
||||
def _split_text(text: str, limit: int) -> List[str]:
|
||||
"""Split ``text`` into <= ``limit``-char chunks on line, then hard, boundaries."""
|
||||
"""Split ``text`` into <= ``limit``-char chunks on line, then hard, boundaries.
|
||||
|
||||
Chunks are fence-balanced: when a split lands inside a ``` code span that
|
||||
survived into section text (the renderer normally routes fenced blocks to
|
||||
``rich_text_preformatted``, but mrkdwn text can still carry fences), the
|
||||
fence is closed at the end of the chunk and reopened on the next so each
|
||||
section renders correctly on its own.
|
||||
"""
|
||||
if len(text) <= limit:
|
||||
return [text]
|
||||
# Reserve headroom for the close/reopen markers the balancing pass adds.
|
||||
split_limit = max(limit - 8, limit // 2, 1) if "```" in text else limit
|
||||
out: List[str] = []
|
||||
remaining = text
|
||||
while len(remaining) > limit:
|
||||
cut = remaining.rfind("\n", 0, limit)
|
||||
while len(remaining) > split_limit:
|
||||
cut = remaining.rfind("\n", 0, split_limit)
|
||||
if cut <= 0:
|
||||
cut = limit
|
||||
cut = split_limit
|
||||
out.append(remaining[:cut])
|
||||
remaining = remaining[cut:].lstrip("\n")
|
||||
if remaining:
|
||||
out.append(remaining)
|
||||
if len(out) > 1 and "```" in text:
|
||||
balanced: List[str] = []
|
||||
reopen = False
|
||||
for chunk in out:
|
||||
if reopen:
|
||||
chunk = "```\n" + chunk
|
||||
odd = chunk.count("```") % 2 == 1
|
||||
if odd:
|
||||
chunk += "\n```"
|
||||
reopen = odd
|
||||
balanced.append(chunk)
|
||||
out = balanced
|
||||
return out
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue