Skip to content

feat(feishu): render markdown headings, tables, and horizontal rules …#32455

Open
lzcopyer wants to merge 1 commit into
NousResearch:mainfrom
lzcopyer:feat/feishu-card-rendering
Open

feat(feishu): render markdown headings, tables, and horizontal rules …#32455
lzcopyer wants to merge 1 commit into
NousResearch:mainfrom
lzcopyer:feat/feishu-card-rendering

Conversation

@lzcopyer

@lzcopyer lzcopyer commented May 26, 2026

Copy link
Copy Markdown

…as interactive cards

Feishu post-type 'md' elements do not support headings (##), pipe tables (|...|), or horizontal rules (---). Previously, these were either stripped to plain text or rendered incorrectly.

This change routes messages containing headings, tables, or HRs to Feishu interactive cards, which support native components:

  • Heading → div element with lark_md bold text

  • | table | → native table element ({name: value} row objects)
  • --- → hr element
  • Other markdown → markdown element (preserves code blocks, lists, etc.)

Fenced code blocks are tracked so | and --- inside them are preserved as literal text rather than being split into separate elements.

Also adds detailed API error logging when interactive cards are rejected, showing the error code and message for easier debugging.

Tests: 210 feishu adapter tests pass (added 7 new card rendering tests)

What does this PR do?

Fixes Feishu message rendering for Markdown headings, pipe tables, and horizontal rules. Previously, these Markdown elements were either stripped to plain text or rendered incorrectly because Feishu's post message type does not support them.

This PR routes messages containing headings (##), pipe tables (|...|), or horizontal rules (---) to Feishu interactive cards, where they are rendered using native card components:

Markdown Card Component Notes
## Heading div + lark_md bold Headings become bold text in a div
| table | native table Uses {column_name: value} row objects per Feishu spec
--- hr Native horizontal rule
Other markdown markdown Code blocks, lists, bold, italic, links preserved

Fenced code blocks are tracked so --- and | inside them are preserved as literal text — they are not falsely split into separate card elements.

Related Issue

N/A (no existing issue)

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

gateway/platforms/feishu.py (+183 lines)

  1. New regex patterns (_MARKDOWN_HEADING_RE, _MARKDOWN_HR_RE) — detect headings and horizontal rules for routing to card format
  2. _build_outbound_payload() — routes headings/tables/HRs to interactive card instead of text or post
  3. _build_card_payload() — builds the card JSON with header + parsed elements
  4. _build_card_elements() (new static method) — parses markdown content into div/table/hr/markdown elements with code block tracking
  5. _build_card_table_element() (new static method) — converts pipe-table lines to Feishu's {name: value} row object format
  6. Send/update fallback handling — when interactive cards are rejected, falls back to plain text instead of failing
  7. Enhanced error logging — logs API error code + message when interactive cards are rejected

tests/gateway/test_feishu.py (+66 lines)

Added 7 new tests and updated 2 existing tests:

  • test_build_card_elements_converts_horizontal_rules_to_hr — verifies HR → hr element
  • test_build_card_elements_preserves_hr_inside_code_blocks — verifies --- in fenced blocks stays literal
  • test_send_uses_card_for_markdown_heading — verifies ## routes to interactive card with div element
  • test_send_uses_card_for_markdown_table — verifies table routing to card
  • test_build_card_payload_custom_header — verifies custom card header
  • test_build_card_payload_exception_fallback — verifies fallback on card rejection
  • test_edit_message_card_fallback_to_plain_text — verifies edit fallback

How to Test

  1. Send a Feishu message containing ## Heading, pipe tables, and ---:
    Test Heading
A B
1 2

  1. Verify the heading renders as bold text (not raw ##)
  2. Verify the table renders as a native Feishu table
  3. Verify the horizontal rule renders as a separator line
  4. Verify code blocks containing --- or | are not split
    Run tests: python -m pytest tests/gateway/test_feishu.py -q (210 passed)

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I've run pytest tests/gateway/test_feishu.py and all 210 tests pass
  • I've added tests for my changes (7 new + 2 updated)
  • I've tested on my platform: Ubuntu 24.04 (WSL), Feishu 7.x

Documentation & Housekeeping

  • I've updated relevant documentation — docstrings added for all new methods
  • I've updated cli-config.yaml.example — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md — N/A
  • I've considered cross-platform impact — N/A (Feishu-specific)
  • I've updated tool descriptions/schemas — N/A

Screenshots / Logs

Gateway logs showing successful interactive card delivery (no rejection/fallback):
2026-05-26 14:28:09 INFO [Feishu] Connected in websocket mode
...no "Interactive card rejected" errors in logs...

The card is accepted by Feishu API and renders correctly with native table, bold headings, and horizontal rules.

…as interactive cards

Feishu post-type 'md' elements do not support headings (##),
pipe tables (|...|), or horizontal rules (---). Previously, these
were either stripped to plain text or rendered incorrectly.

This change routes messages containing headings, tables, or HRs to
Feishu interactive cards, which support native components:

- ## Heading → div element with lark_md bold text
- | table | → native table element ({name: value} row objects)
- --- → hr element
- Other markdown → markdown element (preserves code blocks, lists, etc.)

Fenced code blocks are tracked so | and --- inside them are preserved
as literal text rather than being split into separate elements.

Also adds detailed API error logging when interactive cards are
rejected, showing the error code and message for easier debugging.

Tests: 210 feishu adapter tests pass (added 7 new card rendering tests)
@lzcopyer

Copy link
Copy Markdown
Author

Fixes Feishu message rendering for Markdown headings, pipe tables, and horizontal rules. Previously, these Markdown elements were either stripped to plain text or rendered incorrectly because Feishu's post message type does not support them.

@lzcopyer lzcopyer closed this May 26, 2026
@lzcopyer lzcopyer reopened this May 26, 2026
@alt-glitch alt-glitch added P2 Medium — degraded but workaround exists type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter labels May 26, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #12114 (canonical Feishu markdown table → card rendering PR), tracked by consolidation issue #27469.

This is part of a 70+ PR cluster all implementing Feishu interactive card rendering for markdown tables/headings. See #27469 for the full list of competing PRs (#25453, #29630, #31056, #30928, #31038, #31804, #32488, etc.).

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/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants