fix(feishu): render markdown tables via cards - #28837
Conversation
Route Feishu markdown replies containing tables to Card JSON 2.0 interactive messages so tables render natively instead of forcing the whole reply to plain text. Keep regular markdown replies on post messages and add tests for table routing.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the Feishu table-rendering fix. The underlying bug is still real on current main: gateway/platforms/feishu.py:4380-4382 detects markdown tables and sends them as raw text.
Problems
- The implementation does not match the PR summary’s “CardKit table elements” claim. The diff builds one Card JSON 2.0 markdown element with the original content (
gateway/platforms/feishu.py:580-581in the PR diff), not nativetablecomponents or parsed rows. - Routing tables to
interactivedrops the existing visibility fallback on card failure. Current fallback logic only handles rejectedpostpayloads insend()andedit_message()(gateway/platforms/feishu.py:1811-1820,gateway/platforms/feishu.py:1850-1855), while the PR’s table path becomesinteractiveatgateway/platforms/feishu.py:4312in the diff.
Suggested changes
- Either implement native CardKit
tableelements with row/column tests, or update the PR scope to the simpler card-markdown approach. - Add interactive → text fallback coverage for send and edit failures.
- Please cross-check the final shape against the canonical thread noted in the PR discussion (#12114 / #27469) and the newer current-main consolidation PR #46472.
Automated hermes-sweeper review.
| "elements": [ | ||
| { | ||
| "tag": "markdown", | ||
| "content": content, |
There was a problem hiding this comment.
This sends the raw GFM table through a single card markdown element rather than converting rows into native CardKit table elements, so it does not implement the PR summary’s stated table-element path.
| if _MARKDOWN_TABLE_RE.search(content): | ||
| text_payload = {"text": content} | ||
| return "text", json.dumps(text_payload, ensure_ascii=False) | ||
| return "interactive", _build_markdown_card_payload(content) |
There was a problem hiding this comment.
Once table messages become interactive, they no longer hit the existing post-only fallback paths; add interactive → text fallback so a rejected card does not become a failed/no-message send.
| payload["body"]["elements"], | ||
| [ | ||
| { | ||
| "tag": "markdown", |
There was a problem hiding this comment.
This test locks in a card markdown element, but the PR claims CardKit table elements; if native table rendering is the intended fix, assert a table component and parsed rows instead.
Summary
Motivation
Feishu post messages do not reliably render Markdown tables. The previous workaround forced any reply containing a table to plain text, which preserved the raw content but stripped normal Markdown formatting and left tables unrendered.
This keeps the existing post path for normal Markdown while using an interactive card only when a markdown table is detected.
Fixes #25452
Refs #23938, #27469, #26658, #27695
Test plan
Result locally: