Skip to content

fix(feishu): render markdown tables via cards - #28837

Open
Rocky-Y008 wants to merge 1 commit into
NousResearch:mainfrom
Rocky-Y008:fix/feishu-markdown-table-rendering
Open

fix(feishu): render markdown tables via cards#28837
Rocky-Y008 wants to merge 1 commit into
NousResearch:mainfrom
Rocky-Y008:fix/feishu-markdown-table-rendering

Conversation

@Rocky-Y008

Copy link
Copy Markdown

Summary

  • route Feishu/Lark markdown replies containing GFM-style tables to Card JSON 2.0 interactive messages
  • render table rows as CardKit table elements instead of forcing the whole reply to plain text
  • keep non-table markdown replies on the existing post-message path
  • add regression coverage for table detection/routing and regular markdown behavior

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

python -m pytest tests/gateway/test_feishu.py -q

Result locally:

200 passed, 2 warnings

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.
@daimon-nous daimon-nous Bot added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter P2 Medium — degraded but workaround exists labels May 19, 2026
@daimon-nous

daimon-nous Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Duplicate of #12114 (canonical PR for Feishu markdown table → card rendering). See also consolidation issue #27469 which tracks the full cluster of competing PRs for this feature.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-581 in the PR diff), not native table components or parsed rows.
  • Routing tables to interactive drops the existing visibility fallback on card failure. Current fallback logic only handles rejected post payloads in send() and edit_message() (gateway/platforms/feishu.py:1811-1820, gateway/platforms/feishu.py:1850-1855), while the PR’s table path becomes interactive at gateway/platforms/feishu.py:4312 in the diff.

Suggested changes

  • Either implement native CardKit table elements 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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
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 sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feishu channel displays markdown tables as raw source code instead of rendering them

2 participants