Skip to content

fix(feishu): stop downgrading messages with tables to plain text - #52986

Open
BravianZhao wants to merge 1 commit into
NousResearch:mainfrom
BravianZhao:fix/feishu-table-render-downgrade
Open

fix(feishu): stop downgrading messages with tables to plain text#52986
BravianZhao wants to merge 1 commit into
NousResearch:mainfrom
BravianZhao:fix/feishu-table-render-downgrade

Conversation

@BravianZhao

Copy link
Copy Markdown

Summary

FeishuAdapter._build_outbound_payload force-routes any message containing a markdown table to msg_type=text to avoid an old blank-message bug. Side-effect: every other markdown feature in the same reply -- headings, bold, fenced code, inline code, links, lists -- also gets stripped, because the whole message becomes plain text.

A research summary that happens to include one comparison table comes out as a wall of raw **bold**, `code`, ## heading and |---| characters.

Root cause

The protective table-downgrade dates back to a real client bug, but Feishu's post-type md element renders markdown tables natively on lark-oapi 1.5.x + Feishu/Lark client V7+. The downgrade is now pessimistic: it punishes every non-table markdown element in the message to guard against a problem that no longer exists.

Fix

Route any markdown content (tables included) through the existing _build_markdown_post_payload pipeline. _build_markdown_post_rows already splits on fenced code, so tables now coexist with prose, code, links, and emoji in a single message.

-        if _MARKDOWN_TABLE_RE.search(content):
-            text_payload = {"text": content}
-            return "text", json.dumps(text_payload, ensure_ascii=False)
-        if _MARKDOWN_HINT_RE.search(content):
+        if _MARKDOWN_HINT_RE.search(content) or _MARKDOWN_TABLE_RE.search(content):
             return "post", _build_markdown_post_payload(content)

_MARKDOWN_TABLE_RE is kept (as a hint that table-only content is still markdown) so a bare table without any other markdown still flows through post instead of falling to plain text.

Verification

Verified on Feishu desktop (China region, Lark domain) with lark-oapi 1.5.3 by sending the same composite reply twice -- once as text, once as post:

  • Composite content: two markdown tables (right-aligned numerics, emoji), a fenced Python code block, ## headings, **bold**, bulleted list, inline `code`, and a [link](https://...).
  • msg_type=text (old behaviour): everything renders as literal markdown characters.
  • msg_type=post (new behaviour): every feature including both tables renders natively.

Tests added in tests/gateway/test_feishu.py::TestOutboundPayloadRouting:

Test Input Expected
test_plain_text_uses_text_msg_type "hello world" text
test_plain_markdown_uses_post_msg_type **bold** + link post
test_markdown_table_alone_uses_post_msg_type bare 2x2 table post (regression)
test_markdown_table_with_surrounding_content_keeps_post heading + bold + table + code post (regression)

All 4 pass on Python 3.11.15:

tests/gateway/test_feishu.py::TestOutboundPayloadRouting::test_markdown_table_alone_uses_post_msg_type PASSED
tests/gateway/test_feishu.py::TestOutboundPayloadRouting::test_markdown_table_with_surrounding_content_keeps_post PASSED
tests/gateway/test_feishu.py::TestOutboundPayloadRouting::test_plain_markdown_uses_post_msg_type PASSED
tests/gateway/test_feishu.py::TestOutboundPayloadRouting::test_plain_text_uses_text_msg_type PASSED
======================== 4 passed in 11.18s ========================

Rollback

Single-file fix in plugins/platforms/feishu/adapter.py. Revert the commit to restore the previous downgrade behaviour if a regression on an older Feishu client is reported.

Risk

Low. The post path was already in use for every other markdown message; this PR only widens the input set it accepts. If an old client without table support exists in the wild, the table cells fall through as plain text inside an otherwise correctly rendered post message -- strictly better than today's outcome where the entire message degrades to raw markdown.

The Feishu post-type 'md' renderer now handles markdown tables natively
on lark-oapi 1.5.x + Feishu/Lark client V7+, but _build_outbound_payload
was still force-routing any message containing a table to msg_type=text
to avoid a (long-fixed) blank-message bug.

The unintended side-effect: every other markdown feature in the same
reply -- headings, bold, fenced code, inline code, links, lists -- also
got stripped because the whole message became plain text. A research
summary that happened to include one comparison table came out as a wall
of raw markdown.

Route markdown content (tables included) through the existing
_build_markdown_post_payload pipeline. _build_markdown_post_rows already
splits on fenced code, so tables now render alongside prose, code, and
emoji in a single message.

Verified on Feishu desktop (China region, Lark domain) with lark-oapi
1.5.3: two markdown tables with right-aligned numerics and emoji, a
fenced Python code block, headings, bold, lists, inline code, and a link
all render correctly in one reply.

Adds 4 unit tests covering plain text, plain markdown, bare table, and
composite-with-table routing decisions.
@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/feishu Feishu / Lark adapter P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages duplicate This issue or pull request already exists labels Jun 26, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #52790 — same minimal mechanism (stop force-downgrading table-bearing markdown to msg_type=text; route it through the existing post+md payload path in plugins/platforms/feishu/adapter.py) and same file. #52790 is the earlier open twin for this exact approach. Related to the broader Feishu-table cluster (#52046 issue; native-Card-table approaches #46727/#37728; aggressive rewrite #28030; #27922). A human should pick one PR from the cluster.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 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 duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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.

4 participants