fix(feishu): render Markdown tables as v2 cards instead of degrading to text#37728
Open
315zuicai wants to merge 1 commit into
Open
fix(feishu): render Markdown tables as v2 cards instead of degrading to text#37728315zuicai wants to merge 1 commit into
315zuicai wants to merge 1 commit into
Conversation
…to text Feishu IM 'post' messages do not render Markdown tables — a reply that contains a `| a | b |` table previously surfaced the raw source characters to the user, because `_build_outbound_payload` force-degraded any table-bearing content to plain text. This wraps replies containing a Markdown table into a minimal v2 interactive card with `tag: markdown` elements (which DO render tables correctly on Feishu clients). If card construction raises, the existing text fallback is preserved so the send pipeline cannot crash. Also tightens the Feishu prompt directive in `agent/prompt_builder.py` to explicitly enumerate which Markdown features Feishu IM does and does not render, steering the model toward formats that survive the IM renderer (e.g. bullet-list key-value pairs instead of pipe tables, bold lines instead of ATX headings). Tests: adds 4 cases to `TestFeishuAdapterMessaging` covering the table → card wrap, the build-failure fallback to text, the no-table regression (still uses post), and the plain-text passthrough.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Feishu IM
postmessages do not render Markdown tables — they appear blank or as raw| a | b |source characters on the client. Before this change,FeishuAdapter._build_outbound_payloadreacted by force-degrading any table-bearing reply to plain text, which still surfaced the raw pipe/dash characters to the user.This makes any agent that emits a markdown table (very common — comparison tables, status reports, structured data) look broken on Feishu.
Fix
Two parts:
A)
gateway/platforms/feishu.py— when the outbound content contains a Markdown table, wrap it into a minimal v2 interactive card (schema: 2.0) whose body is one or moretag: markdownelements. Feishu's card markdown elements DO render tables correctly. If the card build raises for any reason, the existing plain-text fallback is preserved so the send pipeline cannot crash.Two helpers are added:
_split_markdown_for_card_elements()— splits long content into chunks that fit Feishu's per-element soft limit (~3400 chars) and per-card element cap (40), respecting fenced code blocks._build_table_card_payload()— wraps the (chunked) markdown into the minimal card v2 envelope.B)
agent/prompt_builder.py— tightens the Feishu directive injected into the system prompt so the model knows which Markdown features Feishu IM actually renders. The previous wording (“Feishu renders Markdown … bold, italic, code blocks, and links are supported”) was misleading because it implied tables/headings work too. New wording explicitly lists what works (**bold**,*italic*, code, links, lists) and what doesn’t (tables, ATX headings, block quotes, hr), and recommends key-value bullet lists or bold lines as safe alternatives. This is best-effort steering — the code-side fix in (A) catches the cases where the model still emits a table.Behaviour change
| a | b |source.Tests
Adds 4 cases to
TestFeishuAdapterMessagingintests/gateway/test_feishu.py:test_build_outbound_payload_wraps_table_into_v2_card— table input produces("interactive", <v2 card with tag:markdown elements>).test_build_outbound_payload_falls_back_to_text_when_card_build_fails—_build_table_card_payloadraising → returns("text", ...)instead of crashing.test_build_outbound_payload_non_table_markdown_still_uses_post— non-table markdown still routes to the existingpostpath.test_build_outbound_payload_plain_text_unchanged— plain text stays as text.All 361 existing tests in
test_feishu.py+test_feishu_bot_admission.py+test_stream_consumer.pycontinue to pass.Validation
Verified live in a real Feishu IM session: a reply containing a 3-row × 4-col Markdown table previously rendered as raw source; with this change it renders as an interactive card with the table laid out correctly.
Diff size
agent/prompt_builder.py: +13 / -2gateway/platforms/feishu.py: +124 / -3 (two new module-level helpers + a small change in_build_outbound_payload)tests/gateway/test_feishu.py: +78 / -0