Skip to content

feat(feishu): render markdown tables as native Card JSON 2.0 table components#40445

Open
highland0971 wants to merge 2 commits into
NousResearch:mainfrom
highland0971:feat/feishu-native-table-rendering-v2
Open

feat(feishu): render markdown tables as native Card JSON 2.0 table components#40445
highland0971 wants to merge 2 commits into
NousResearch:mainfrom
highland0971:feat/feishu-native-table-rendering-v2

Conversation

@highland0971

Copy link
Copy Markdown

Summary

This PR routes GFM markdown table content to Feishu Card JSON 2.0 interactive cards with native table components (tag: "table"), replacing the current behavior that force-degrades ALL table-bearing messages to plain text.

Problem

Feishu post-type md elements do not render markdown tables — the message appears blank. The current fix (#20275) force-degrades the ENTIRE message to plain text (msg_type="text"), losing all formatting (headings, bold, code blocks).

Solution

Three-layer architecture combining the best of existing community PRs:

Layer Approach Source
Routing Conservative — only table content → interactive card, non-table keeps post/text Own design
Rendering Native table component (columns, rows, header_style, page_size=5) Adapted from #38453
Splitting Card splitting when >5 tables (Feishu API limit), paragraph-boundary smart segmentation Adapted from #33310
Fallback Triple coverage: send() exception + response + edit_message + _feishu_send_with_retry Own design

Key design decisions

Changes

gateway/platforms/feishu.py (~310 lines changed)

  • _parse_markdown_table() — GFM table lines → Feishu table component JSON
  • _split_content_and_tables() — line scanner producing mixed [{md}, {table}, {md}] elements
  • _split_content_by_table_limit() — split by 5-table card limit with paragraph boundary awareness
  • _build_table_card_payload() — build Card JSON 2.0 with mixed elements
  • _build_outbound_payloads() — multi-card expansion for >5 tables
  • _POST_CONTENT_INVALID_RE expanded to match interactive card errors
  • send() / edit_message() / _feishu_send_with_retry — all extended to cover interactive msg_type

Testing

  • 229 tests pass: 24 new unit tests + 205 existing tests (zero regression)
  • New tests cover: table parsing (11 cases), line scanning (4 cases), card splitting (3 cases), routing & payload (6 cases)
  • E2E verified on production Feishu workspace

Comparison with existing PRs

Feature This PR #33310 #38453 #37728 #35906 #35781
Native table component
Card splitting (5-table limit)
Conservative routing
Triple fallback
Zero regression tests

Closes #9549. Closes #19035.
Supersedes #33310 and #38453 by combining their strengths while avoiding their weaknesses.

Routes GFM table content to Feishu Card JSON 2.0 interactive cards
with native `table` components instead of degrading to plain text.

Key features:
- Native table component rendering (tag:table with header_style)
- Conservative routing: only table content → interactive card,
  non-table content keeps post/text path (zero regression)
- Card splitting: max 5 tables per card per Feishu API docs,
  auto-splits into multiple cards with paragraph-boundary awareness
- Triple fallback: send() exception + response + edit_message +
  _feishu_send_with_retry all cover interactive→text degradation
- page_size=5 per Feishu official docs ([1,10] range)

Verified: 229 tests pass (24 new + 205 existing, zero regression).
Deployed and E2E-tested on production Feishu workspace.

Combines the best of NousResearch#33310 (card splitting framework) and
NousResearch#38453 (native table parsing), avoiding the pitfalls of both:
- NousResearch#33310's markdown-table rendering → native table components
- NousResearch#38453's aggressive all-interactive routing → conservative routing

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Comment — New integration behavior

Adds Feishu markdown table rendering as native Card JSON 2.0 table components (228 additions, 44 deletions). This changes how markdown tables are serialized in the Feishu gateway.

Observations

  • 44 deletions suggest table rendering logic was restructured, not just added to
  • The Card JSON 2.0 conversion appears to be a new mapping layer

Suggestions for formal review

  • Add a test with a representative markdown table (including edge cases: empty cells, colspan, rowspan) and assert the generated Card JSON structure
  • Verify that tables previously rendered via the old path still look correct in Feishu
  • Document the Card JSON 2.0 schema differences from previous versions

Once edge-case tests are confirmed, this should be ready for APPROVE.

Reviewed by Hermes Agent

@alt-glitch alt-glitch added type/feature New feature or request platform/feishu Feishu / Lark adapter P3 Low — cosmetic, nice to have labels Jun 6, 2026
…JSON 2.0 schema docs

Addresses review feedback from tonydwb on PR NousResearch#40445:

1. Edge case tests (empty cells, markdown formatting, column mismatch,
   wide tables, header-only tables, non-table pipe lines, empty content)

2. Regression tests (plain text path unchanged, markdown hints still
   use post type, Card JSON conforms to Feishu schema)

3. Card JSON 2.0 schema documentation (v1.0 vs v2.0 differences,
   table component spec, wide_screen_mode, data_type: markdown)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feishu] Code blocks cannot be expanded — only first ~2 lines visible [Feishu] Markdown tables not rendering in Feishu messages

3 participants