Skip to content

fix(feishu): render markdown tables correctly via post+md instead of downgrading to text#31056

Open
luochonglie wants to merge 4 commits into
NousResearch:mainfrom
luochonglie:fix/feishu-markdown-table-rendering
Open

fix(feishu): render markdown tables correctly via post+md instead of downgrading to text#31056
luochonglie wants to merge 4 commits into
NousResearch:mainfrom
luochonglie:fix/feishu-markdown-table-rendering

Conversation

@luochonglie

Copy link
Copy Markdown

Summary

The Feishu gateway adapter had two bugs causing markdown tables to display as raw pipe-delimited text (| A | B |) instead of rendered tables:

Bug 1: Incorrect table downgrade in _build_outbound_payload()

The code forced text mode for content matching _MARKDOWN_TABLE_RE, based on the assumption that post+md would render tables as blank messages:

# Feishu post-type md elements do not render markdown tables; sending
# table content as post causes the message to appear blank on the client.
# Force plain text for anything that looks like a markdown table.
if _MARKDOWN_TABLE_RE.search(content):
    text_payload = {"text": content}
    return "text", json.dumps(text_payload, ensure_ascii=False)

This assumption is incorrect. Tested and verified that Feishu post+md renders tables correctly. Lark CLI --markdown uses the same post+md format ({"zh_cn":{"content":[[{"tag":"md","text":"..."}]]}}) and tables render perfectly.

Bug 2: _MARKDOWN_HINT_RE missing table pattern

_MARKDOWN_HINT_RE determines whether content should be sent as post (rich text) or text (plain text). It matches headings, bold, code blocks, lists, links, etc. — but not tables.

This means content containing ONLY a table (without other markdown elements like headings or bold) would not match _MARKDOWN_HINT_RE and fall through to plain text mode, displaying raw pipe characters.

Changes

  1. Remove _MARKDOWN_TABLE_RE downgrade logic in _build_outbound_payload() — tables now correctly route to post format
  2. Add table pattern (^\|.*\|\n\|[-|: ]+\|) to _MARKDOWN_HINT_RE — pure-table content is now correctly detected and sent as post

Testing

Verified on Feishu mobile client (dark mode):

Before After
Raw pipe characters visible Tables render correctly with borders and cell divisions
Pure table → text mode Pure table → post mode
Table + other md → post (worked by accident) All tables → post (works by design)

Also verified with Lark CLI that both --as bot and --as user identities render tables correctly via post+md format.

…downgrading to text

The Feishu gateway adapter had two bugs causing markdown tables to display
as raw pipe-delimited text instead of rendered tables:

1. _build_outbound_payload() forced text mode for content matching
   _MARKDOWN_TABLE_RE, based on the incorrect assumption that post+md
   would render tables as blank messages. Tested and proven wrong —
   Feishu's post+md renders tables correctly (verified with Lark CLI
   --markdown which uses the same post+md format).

2. _MARKDOWN_HINT_RE did not include a table pattern, so content
   containing ONLY a table (without other markdown like headings, bold,
   etc.) would not match and fall through to plain text mode.

Fixes:
- Remove the _MARKDOWN_TABLE_RE downgrade logic in _build_outbound_payload()
- Add table pattern (^\|.*\|\n\|[-|: ]+\|) to _MARKDOWN_HINT_RE
  so pure-table content is correctly routed to post format
@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter P2 Medium — degraded but workaround exists labels May 23, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of the Feishu markdown table rendering family. Root issues: #9549, #26658, #27469 (consolidation issue). Competing fix PRs: #26108, #27739, #29552, #28030, #29166. This PR and #29552 take the same approach (post+md + table pattern in _MARKDOWN_HINT_RE).

@jsboige

jsboige commented May 23, 2026

Copy link
Copy Markdown

Review: fix(feishu): render markdown tables correctly via post+md instead of downgrading to text

Summary

Two-part fix: (1) removes an incorrect downgrade that forced text mode for markdown tables (the assumption that post+md renders tables as blank was wrong), and (2) adds a table pattern to _MARKDOWN_HINT_RE so that pure-table content (no headings/bold/etc.) is correctly detected as rich text. The core logic change is correct and well-motivated.

Analysis

Correctness: The behavioral change is sound. Removing the _MARKDOWN_TABLE_RE guard in _build_outbound_payload allows tables to reach the post+md path. Adding the table alternation to _MARKDOWN_HINT_RE ensures that content containing only a table matches the hint regex and takes the post path. Both fix the stated bugs.

Edge cases checked:

  • Standard tables, aligned tables (:---, ---:, :---:), multi-column, single-column: all match the new pattern correctly.
  • Table after preceding text: matches (the ^ in MULTILINE mode matches start-of-line, not just start-of-string).

Issues Found

WARNING (2)

# Location Issue Detail
1 Line 156-158 (regex definitions) Dead code left behind _MARKDOWN_TABLE_RE is still defined at the module level but has no remaining callers after this PR. The comment above it ("Feishu post-type 'md' elements do not render tables, so we force text mode") is also now stale/misleading. Should be removed in a follow-up or here.
2 Line 153 (new table alternation in _MARKDOWN_HINT_RE) CRLF line endings not handled The pattern `(^|.*|\n|[-

INFO (2)

# Location Suggestion
1 _build_outbound_payload (line 4225-4229) The comment block is verbose for a permanent code artifact. Consider condensing to 1-2 lines since git history preserves the full context of what was removed and why.
2 Test coverage There are no unit tests for _build_outbound_payload or _MARKDOWN_HINT_RE that verify table content routes to post mode. Given this was a regression (incorrect assumption), adding a regression test would prevent it from recurring. The test file tests/gateway/test_feishu.py seems like the right place.

Points Positifs

  • The PR body is excellent: clear problem statement, root cause analysis for both bugs, and testing evidence with screenshots.
  • Minimal diff: only touches the exact code paths responsible for the bug, no unnecessary changes.
  • The approach (fix the routing instead of working around it) is the right design.

Recommendation

COMMENT -- The fix is correct and safe to merge functionally. The two WARNINGs (dead _MARKDOWN_TABLE_RE constant + CRLF edge case) are non-blocking but worth addressing before or shortly after merge. A regression test for the table routing would be a valuable addition.

…LF handling

- Remove dead _MARKDOWN_TABLE_RE constant and stale comment (WARNING NousResearch#1)
- Fix CRLF line ending handling in _MARKDOWN_HINT_RE pattern (WARNING NousResearch#2)
- Fix CRLF handling in _escape_markdown_text() - use re.split(r'\r?\n')
- Preserve original line ending style when rejoining lines

Addresses review feedback from jsboige in PR NousResearch#31056
@luochonglie

Copy link
Copy Markdown
Author

🔧 WARNINGs Fixed - PR Updated

Thanks @jsboige for the detailed review! I've addressed both WARNINGs:

✅ WARNING #1: Dead Code Removed

  • Deleted _MARKDOWN_TABLE_RE constant (no callers after this PR)
  • Removed stale comment about Feishu not rendering tables

✅ WARNING #2: CRLF Line Ending Support

Fixed in 3 places:

  1. _MARKDOWN_HINT_RE pattern: Changed \n to \r?\n to match both LF and CRLF
  2. _escape_markdown_text(): Changed split('\n') to re.split(r'\r?\n') for robust line splitting
  3. Return statement: Added smart line ending preservation - detects original style and preserves it

📝 Commit Info

  • New commit: d38b6f055 - "fix(feishu): address code review warnings - remove dead code + fix CRLF handling"
  • PR now has 3 commits: All fixes cleanly separated

🙏 Additional Notes

  • Regarding INFO Support passing morph snapshot id #2 (unit tests): Agreed this would be valuable - happy to add in a follow-up PR since this one already has 3 commits
  • The CRLF fix ensures tables from Windows clients/APIs work correctly now

Ready for re-review! 🚀


@alt-glitch Thanks for noting this is in the "feishu markdown table rendering family" - this PR was developed independently but I'll review #29552 to see if there are any improvements we can incorporate.

Add comprehensive unit tests for the Feishu markdown table rendering fix:
- Test _MARKDOWN_HINT_RE table pattern detection (LF, CRLF, alignment)
- Test _escape_markdown_text() smart table detection and preservation
- Test CRLF (Windows line ending) handling throughout
- Test edge cases: emoji, special chars, wide tables, code blocks
- Test regression scenarios from reported issues (Zhipu usage, Feishu seen messages)

25 test cases covering all aspects of the fix to prevent regression.

Addresses INFO NousResearch#2 from jsboige review in PR NousResearch#31056: adds unit tests for table routing.
@luochonglie

Copy link
Copy Markdown
Author

✅ Unit Tests Added!

Thanks for the review feedback @jsboige! I've addressed the INFO #2 - unit tests are now included.

📝 Test Coverage

Created 25 comprehensive unit tests in tests/gateway/test_feishu_markdown_table.py:

Test Class Tests Coverage
TestMarkdownHintRETablePattern 6 Table pattern detection (LF, CRLF, alignment)
TestEscapeMarkdownTextTableDetection 7 Smart table detection, cell formatting preservation
TestCRLFHandling 5 Windows line ending support
TestTableEdgeCases 6 Emoji, special chars, wide tables, code blocks
TestRegressionScenarios 2 Real-world tables from production (Zhipu usage, Feishu seen messages)

🧪 Test Results

25 passed, 2 warnings in 1.97s

📦 New Files

  • tests/gateway/test_feishu_markdown_table.py - 293 lines of test code

🎯 What the Tests Verify

  • ✅ Tables render correctly in Feishu (no more raw pipe text)
  • ✅ CRLF line endings are handled properly
  • ✅ Table cells preserve inline markdown (**bold**, `code`, etc.)
  • ✅ Edge cases: emoji in tables, wide tables, empty cells
  • ✅ Regression prevention for the specific issues reported

All WARNINGs and INFOs from the review have been addressed! 🚀

@luochonglie

Copy link
Copy Markdown
Author

Gentle ping 🎯

This PR fixes a Feishu/Lark markdown table rendering bug affecting all markdown tables sent to the platform.

Verified fixes:

  • Tables now render correctly with borders and cell divisions
  • Pure table content correctly routes to post mode
  • All table types work by design (not by accident)

Would be great if someone could review when time permits. Thanks! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants