feat(feishu): render markdown tables as native Feishu card table components - #46727
feat(feishu): render markdown tables as native Feishu card table components#46727BiuDoom wants to merge 1 commit into
Conversation
Feishu's post/md format does not render GFM markdown tables, so FeishuAdapter._build_outbound_payload previously downgraded any message containing a table to plain text, losing all formatting and showing raw pipe characters to the user. This builds a Feishu card JSON 2.0 message with native table components when outbound content contains a markdown table, while non-table prose is preserved as markdown elements. Table cells use data_type markdown so inline formatting renders; row_height auto + row_max_height prevent truncation. Respects Feishu limits (<=5 tables/card, <=50 columns) and falls back to plain text on any breach, parse failure, or exception, so a message is never dropped. Existing post/text/approval-card paths are unchanged. Adds tests/gateway/test_feishu_table_card.py (17 tests).
870c028 to
c1323e5
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused table-rendering implementation. The underlying issue remains on current main: plugins/platforms/feishu/adapter.py:4524-4534 still downgrades detected tables to plain text.
Problems
- The branch at
gateway/platforms/feishu.py:4582returnsinteractive, but the current send and edit fallback paths only recover rejectedpostpayloads (plugins/platforms/feishu/adapter.py:1913-1936and:1963-1971). A rejected card would therefore fail instead of taking the claimed text fallback. tests/gateway/test_feishu_table_card.py:209-228duplicates the routing logic rather than invoking_build_outbound_payload, so it cannot catch drift in the production method.- The target adapter was relocated by
5600105478ffde29d7566b45421b100eaa29c4eftoplugins/platforms/feishu/adapter.py; this needs a port rather than applying the old-file diff directly.
Suggested changes
- Port the implementation to the bundled adapter and test rejected interactive-card send/edit responses falling back to text.
- Exercise the real adapter payload method in the routing tests.
Automated hermes-sweeper review.
| try: | ||
| card_json = _build_table_card(content) | ||
| if card_json is not None: | ||
| return "interactive", card_json |
There was a problem hiding this comment.
This changes the outbound type to interactive, but the send and edit fallback paths only recover rejected post payloads. Add an interactive-card rejection fallback there as well, with a regression test, so an API-invalid card does not turn into a failed delivery.
| """ | ||
|
|
||
| def _call(self, content): | ||
| # The method is an instance method; replicate its logic via the helpers. |
There was a problem hiding this comment.
This copies _build_outbound_payload instead of exercising it. Instantiate the adapter minimally or use the existing fixture and call the real method, otherwise a later production change can silently diverge from this test.
Problem
Feishu's
post/mdmessage format does not render GFM markdown tables (per Feishu's docs themdtag supports only a subset of markdown, and tables are not included).FeishuAdapter._build_outbound_payloadcurrently detects any markdown table and downgrades the entire message to plaintext, losing all formatting (bold, headings, lists) and showing raw| --- |pipes to the user.Change
When outbound content contains a markdown table, build a Feishu card JSON 2.0 message with native
tablecomponents, while non-table prose is preserved asmarkdownelements._split_content_into_blocks(orders prose / table / fenced-code blocks; code fences are never parsed as tables),_parse_gfm_table(GFM -> columns/rows),_build_table_card(assembles the card).data_type: "markdown"so inline formatting (e.g. bold) renders;row_height: "auto"+row_max_heightso long cells wrap instead of being truncated.post/text/ approval-card paths are unchanged.Tests
tests/gateway/test_feishu_table_card.py(17 tests): block splitting, GFM parsing, card structure, order preservation, fenced-pseudo-table exclusion, >5-table fallback, and_build_outbound_payloadrouting. Existingtest_feishu.py(205) andtest_feishu_approval_buttons.py(38) still pass.