feat(feishu): render markdown tables as native CardKit v2 table components - #17006
feat(feishu): render markdown tables as native CardKit v2 table components#17006chapaofan wants to merge 1 commit into
Conversation
… cards Feishu's built-in markdown parser does not support table syntax - tables render as raw pipe-delimited text. This change adds automatic detection and rendering of markdown tables as native CardKit v2 table components. Changes: - Add _parse_markdown_table() - parses markdown text into segments alternating between text blocks and table structures - Add _build_table_card() - converts parsed table segments into Feishu CardKit v2 table component JSON - Add _build_interactive_card_with_tables() - wraps text+table segments into a full CardKit v2 interactive card payload - Add _convert_markdown_tables_to_code() - deprecated backward-compat no-op fallback for string-based callers - Modify _build_outbound_payload() - before falling through to post or text payload, check for tables and render as interactive card - Modify _build_markdown_post_payload() - call the deprecated backward-compat function for safety
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tackling a real Feishu rendering limitation. Current main still sends recognized Markdown tables as plain text at plugins/platforms/feishu/adapter.py:4524-4534, so the underlying feature remains needed.
Problems
- The diff targets
gateway/platforms/feishu.py, which was moved toplugins/platforms/feishu/adapter.pyby476d8d9cc; this needs a port to the live plugin adapter rather than a clean cherry-pick. _parse_markdown_table()starts a table for any|...|line atgateway/platforms/feishu.py:219; it does not require a separator row. Non-table pipe-delimited prose can therefore become a header-only CardKit table.- The diff adds no tests. The live send/edit fallbacks currently cover only
postfailures (plugins/platforms/feishu/adapter.py:1914,:1963), so a native-card route needs an interactive rejection fallback as well.
Suggested changes
- Port to the plugin adapter, require header-plus-separator detection, and add parser/routing/failure-fallback coverage in
tests/gateway/test_feishu.py.
Automated hermes-sweeper review.
| table_lines = [] | ||
|
|
||
| for line in lines: | ||
| if _MARKDOWN_TABLE_LINE_RE.match(line): |
There was a problem hiding this comment.
This accepts any single pipe-enclosed line as a table. Require a valid header-plus-separator pair before opening a table; otherwise non-table pipe-delimited prose is emitted as a CardKit table.
| # for real table rendering instead of code blocks. | ||
| card = _build_interactive_card_with_tables(content) | ||
| if card is not None: | ||
| return "interactive", json.dumps(card, ensure_ascii=False) |
There was a problem hiding this comment.
The live send/edit fallback paths only retry plain text for rejected post payloads. When porting this interactive route to the current plugin adapter, add equivalent interactive-card failure fallback so a CardKit API rejection does not fail the entire reply.
Summary
Feishu's built-in markdown parser does not support table syntax — tables render as raw pipe-delimited text, which is barely readable. This PR adds automatic detection and rendering of markdown tables as native CardKit v2 table components.
Changes
New functions
_parse_markdown_table(text)— Parses markdown text into segments alternating between text blocks and table structures. Handles leading/trailing pipes, separator rows, and multi-line tables._build_table_card(headers, rows)— Converts parsed table segments into Feishu CardKit v2 table component JSON. Strips markdown bold markers from cell content. Applies a clean header style (bold, left-aligned)._build_interactive_card_with_tables(text)— Wraps text+table segments into a full CardKit v2 interactive card payload. ReturnsNoneif no tables are found, so callers can fall back to the existing post/text payload._convert_markdown_tables_to_code(text)— Deprecated backward-compatibility function (no-op). Previously served as a code-block fallback; now superseded by interactive cards.Modified functions
_build_outbound_payload(content)— Before falling through to post or text payload, checks for markdown tables. If found, sends as"interactive"card type instead._build_markdown_post_payload(content)— Calls the deprecated backward-compat function as a safety net.How it works
When the agent sends a message containing a markdown table like:
Instead of showing raw pipe text, this renders a proper formatted table in the Feishu card. Non-table content before/after the table is also preserved in the same card.
Notes
returnstatement in the original_build_table_cardwas removed (the second bare return after theheader_stylereturn was unreachable).