Skip to content

fix(feishu): render markdown tables via post+md, remove force-text downgrade - #68121

Merged
teknium1 merged 3 commits into
mainfrom
fix/feishu-table-post
Jul 20, 2026
Merged

fix(feishu): render markdown tables via post+md, remove force-text downgrade#68121
teknium1 merged 3 commits into
mainfrom
fix/feishu-table-post

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Feishu markdown tables render as native tables again — this removes the _MARKDOWN_TABLE_RE force-text downgrade in _build_outbound_payload() and routes table-containing messages through the standard post/md pipeline.

Root cause: the downgrade (PR #20275, commit 8e18d10) worked around a Feishu API bug where post-type md elements rendered table-containing messages blank. Feishu has since fixed this server-side — the official docs (updated 2026-07-07) now state post md tags 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_RE now matches a pipe-table header + separator pair, so table-only messages take the post path; the _MARKDOWN_TABLE_RE force-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 contributors

Validation

Content Before After
Table-only message text (raw pipes) post, renders natively
Prose + table + bold text (everything raw) post, all markdown renders
Plain text text text (unchanged)
Single pipe line (not a table) text text (unchanged)
  • scripts/run_tests.sh tests/gateway/test_feishu.py tests/gateway/test_feishu_table_markdown.py → 217 passed, 0 failed
  • E2E: exercised _build_outbound_payload with 7 content shapes against isolated HERMES_HOME — all table variants route to post with content preserved; negative controls stay text
  • Safety net: send() 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 blanking

Resolves 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

feishu-tables-post

JasonFang1993 and others added 3 commits July 20, 2026 08:52
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.
@teknium1
teknium1 merged commit 977884e into main Jul 20, 2026
33 checks passed
@teknium1
teknium1 deleted the fix/feishu-table-post branch July 20, 2026 16:19
This was referenced Jul 20, 2026
@John15Wil

Copy link
Copy Markdown

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: _MARKDOWN_TABLE_RE forced table-containing replies to msg_type=text, exposing raw Markdown in Feishu. The proposed fix likewise routed tables through the existing post + md path and was empirically verified against Feishu.

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.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins platform/feishu Feishu / Lark adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants