Bug description
With platforms.slack.extra.rich_blocks: true, an ordered (numbered) Markdown list whose items are separated by blank lines renders in Slack with every item numbered "1." instead of 1, 2, 3, …
Blank lines between list items are the normal shape of LLM-authored content (e.g. a scheduled briefing with a numbered "Top of Mind" section), so this hits real output, not just contrived input.
Root cause
In plugins/platforms/slack/block_kit.py, render_blocks() groups a contiguous run of list lines into a single rich_text_list element (block_kit.py#L437). The run loop only continues across (a) another bullet/ordered line or (b) an indented continuation line:
if _BULLET_RE.match(line) or _ORDERED_RE.match(line):
...
while i < n:
bm = _BULLET_RE.match(lines[i])
om = _ORDERED_RE.match(lines[i])
if bm: ...
elif om: ...
elif lines[i].strip() and lines[i].startswith((" ", "\t")) and items:
# continuation line of the previous item
...
else:
break # <-- a blank line lands here and ends the run
A blank line (lines[i].strip() == "") falls through to else: break, so the run ends. The next numbered item then starts a new single-item rich_text_list. Slack numbers each rich_text_list independently starting at 1, so N blank-separated items become N separate lists, each rendering "1.".
_list_block itself is correct — the items never reach it as one run.
Steps to reproduce
- Enable rich blocks:
platforms:
slack:
extra:
rich_blocks: true
- Have the agent post a numbered list with blank lines between items, e.g.:
1. First item.
1. Second item.
1. Third item.
(1./1./1. or 1./2./3. — Markdown renders both as 1,2,3; the bug is independent of the authored numbers.)
Minimal renderer-level repro:
from plugins.platforms.slack.block_kit import render_blocks
blocks = render_blocks("1. alpha\n\n1. beta\n\n1. gamma", mrkdwn_fn=lambda s: s)
lists = [(e["style"], e["indent"], len(e["elements"]))
for b in blocks for e in b.get("elements", [])
if e.get("type") == "rich_text_list"]
print(len(blocks), lists)
Expected
One rich_text_list with 3 items → Slack renders 1, 2, 3.
2 [('ordered', 0, 1), ...] # contiguous input already works: 1. a / 2. b / 3. c → one list
Actual
Three separate single-item rich_text_list elements → Slack renders 1, 1, 1.
3 [('ordered', 0, 1), ('ordered', 0, 1), ('ordered', 0, 1)]
Contiguous items (no blank lines) render correctly, confirming blank-line handling is the trigger. Bullet lists are visually unaffected (no numbering to reset), so this is specific to ordered lists.
Suggested fix
Treat a blank line inside a list run as a soft separator that does not terminate the run when the next non-blank line is another list item of the same (indent, ordered) kind — i.e. look past a single blank line before breaking, rather than breaking on it. That keeps a blank-separated numbered list as one rich_text_list, preserving 1, 2, 3.
Environment
hermes-agent==0.18.0 (PyPI wheel)
- Platform: Slack (Socket Mode),
rich_blocks: true
Bug description
With
platforms.slack.extra.rich_blocks: true, an ordered (numbered) Markdown list whose items are separated by blank lines renders in Slack with every item numbered "1." instead of 1, 2, 3, …Blank lines between list items are the normal shape of LLM-authored content (e.g. a scheduled briefing with a numbered "Top of Mind" section), so this hits real output, not just contrived input.
Root cause
In
plugins/platforms/slack/block_kit.py,render_blocks()groups a contiguous run of list lines into a singlerich_text_listelement (block_kit.py#L437). The run loop only continues across (a) another bullet/ordered line or (b) an indented continuation line:A blank line (
lines[i].strip() == "") falls through toelse: break, so the run ends. The next numbered item then starts a new single-itemrich_text_list. Slack numbers eachrich_text_listindependently starting at 1, so N blank-separated items become N separate lists, each rendering "1."._list_blockitself is correct — the items never reach it as one run.Steps to reproduce
1./1./1.or1./2./3.— Markdown renders both as 1,2,3; the bug is independent of the authored numbers.)Minimal renderer-level repro:
Expected
One
rich_text_listwith 3 items → Slack renders 1, 2, 3.Actual
Three separate single-item
rich_text_listelements → Slack renders 1, 1, 1.Contiguous items (no blank lines) render correctly, confirming blank-line handling is the trigger. Bullet lists are visually unaffected (no numbering to reset), so this is specific to ordered lists.
Suggested fix
Treat a blank line inside a list run as a soft separator that does not terminate the run when the next non-blank line is another list item of the same
(indent, ordered)kind — i.e. look past a single blank line before breaking, rather than breaking on it. That keeps a blank-separated numbered list as onerich_text_list, preserving 1, 2, 3.Environment
hermes-agent==0.18.0(PyPI wheel)rich_blocks: true