fix(feishu): render markdown tables via post+md, remove force-text downgrade - #68121
Conversation
Resolves issue #52786 (duplicate of #23938): The `_build_outbound_payload` shortcut forced any message containing a pipe table to ``msg_type=text``. Feishu readers then rendered the raw pipe-and-dash source instead of a table. Empirically current Feishu clients render markdown tables inside ``post``-type ``md`` elements natively, so the downgrade branch had to go. Two changes: 1. ``_MARKDOWN_HINT_RE`` now also matches a pipe-table header+separator pair, so a table-only message is recognised as "has markdown" and takes the ``post`` path. All previously recognised hints (headings, lists, code, bold/italic/strike/underline, links, blockquotes, hr) still match — verified by the existing 205 test_feishu.py cases plus the new regression tests below. 2. ``_build_outbound_payload`` no longer special-cases `_MARKDOWN_TABLE_RE` before the hint check. The hint check now routes table content to `_build_markdown_post_payload`, which is the same path any other markdown structure takes. ``_MARKDOWN_TABLE_RE`` itself is retained as a module-level constant for external callers (import-path-sensitive tests, third-party consumers of the adapter module) and continues to work for its existing uses. Tests ----- New: ``tests/gateway/test_feishu_table_markdown.py`` — four regression tests: - ``test_markdown_table_uses_post_not_text`` — pure-table content reaches ``post`` (issue #52786 scenario). - ``test_table_combined_with_other_markdown_does_not_downgrade`` — prose + table + prose message keeps its surrounding markdown. - ``test_existing_markdown_heading_still_uses_post`` — sanity guard: the heading path is unchanged. - ``test_plain_text_without_markdown_still_uses_text`` — negative control: pure prose still goes to ``text``. Verification ------------ ``pytest tests/gateway/test_feishu.py tests/gateway/test_feishu_table_markdown.py`` passes 209/209 (205 existing + 4 new), three consecutive runs. Rollback -------- ``git reset --hard 44ddc55`` restores upstream main without the new test file.
Route table-shaped Markdown through the existing post/md builder so current Feishu clients render tables instead of showing source markup. Add a direct payload regression test that checks the post message type and decoded md element.
|
For the contribution record, I would like to link the earlier PR #29166, which was opened on May 20, 2026 and identified the same root cause: After the Feishu adapter moved into the bundled plugin path, I rebased #29166 on July 14 and added direct routing regression tests covering plain text, table-only content, and mixed Markdown/table content. The author of duplicate PR #50640 also noted on June 22 that they had independently reached the same fix and that #29166 got there first. I am glad #68121 landed the fix for everyone. Could the maintainers please link #29166 as a related/superseded contribution and, if appropriate, acknowledge it in the contribution history? I am not requesting any code change to the merged implementation—only an accurate link in the record. Thank you. |
Summary
Feishu markdown tables render as native tables again — this removes the
_MARKDOWN_TABLE_REforce-text downgrade in_build_outbound_payload()and routes table-containing messages through the standardpost/mdpipeline.Root cause: the downgrade (PR #20275, commit 8e18d10) worked around a Feishu API bug where post-type
mdelements rendered table-containing messages blank. Feishu has since fixed this server-side — the official docs (updated 2026-07-07) now state postmdtags support CommonMark 0.31 + GFM including tables, and three contributors independently live-verified rendering in July 2026 (#61647 PC+mobile, #58019, #39955). The workaround itself became the bug: any message containing a table lost ALL formatting (headings, bold, links, code) because the entire message was sent as plain text.Salvage of PR #58019 (@JasonFang1993, cleanest implementation with regression tests) and PR #29552 (@M1racleShih, earliest table→post fix against the live plugin adapter path, May 21) — both cherry-picked with authorship preserved.
Changes
plugins/platforms/feishu/adapter.py:_MARKDOWN_HINT_REnow matches a pipe-table header + separator pair, so table-only messages take thepostpath; the_MARKDOWN_TABLE_REforce-text branch is removed (constant retained for external callers)tests/gateway/test_feishu_table_markdown.py: 4 regression tests (table-only → post; prose+table keeps surrounding markdown; heading path unchanged; plain-text negative control)tests/gateway/test_feishu.py: direct payload regression test (post type + decoded md element)contributors/emails/: mappings for both contributorsValidation
text(raw pipes)post, renders nativelytext(everything raw)post, all markdown renderstexttext(unchanged)texttext(unchanged)scripts/run_tests.sh tests/gateway/test_feishu.py tests/gateway/test_feishu_table_markdown.py→ 217 passed, 0 failed_build_outbound_payloadwith 7 content shapes against isolated HERMES_HOME — all table variants route to post with content preserved; negative controls stay textsend()already retries as stripped plain text if the API rejects a post payload (_POST_CONTENT_INVALID_RE), so a tenant lagging the server-side fix degrades gracefully instead of blankingResolves the ~30-issue table-rendering cluster rooted at #9549 (#7022, #7310, #9536, #18704, #21778, #21866, #23938, #25452, #26658, #29245, #32607, #50602, #52046, #52786, #56430, #58269, #61643, and more).
Infographic