Problem
When the Feishu (飞书) channel sends AI responses containing markdown tables, the table syntax is displayed as raw source code instead of being rendered as a visual table.
This is because Feishu's post message type with md tags does not support markdown table syntax. The current workaround (since PR #20275) detects tables and falls back to text type messages, which prevents blank messages but displays the raw markdown.
Reproduction
- Connect Hermes Agent to a Feishu group or DM
- Send a message that triggers a table response, e.g.:
- "请用表格对比 Python 和 Go 的特点"
- "List the pros and cons in a table"
- Observe the response in Feishu client — table syntax shown as
| col1 | col2 |
Root Cause
_build_outbound_payload() in gateway/platforms/feishu.py detects markdown tables via regex and forces msg_type="text", because Feishu's post type md elements render tables as blank.
Proposed Solution
Use Feishu Interactive Cards (msg_type="interactive") with native table components, using Card JSON 2.0 ("schema": "2.0"):
- Parse markdown tables from AI response content
- Split content into "table segments" and "prose segments"
- Convert table segments to Feishu card
table components
- Convert prose segments to card
markdown elements (preserving original markdown — no conversion needed)
- Assemble as a single interactive card message using Card JSON 2.0 structure
Feishu Interactive Cards (JSON 2.0) support:
- Native table rendering with headers, rows, pagination
- Mixed content: markdown text + tables in one card
- Full markdown syntax in
markdown elements: headings, blockquotes, inline code, code blocks, bold, lists, etc.
lark_md column type for rich formatting in table cells
Approach
| Message content |
Current behavior |
Proposed behavior |
| Contains tables |
text (raw source) |
interactive card with table components |
| No tables, has markdown |
post |
post (unchanged) |
| Plain text only |
text |
text (unchanged) |
Safety measures
- Tables inside fenced code blocks (
```) are not parsed
- Card JSON limited to 100KB; falls back to text on overflow
- Max 5 tables per card, 50 columns per table (Feishu API limits)
- Full fallback: interactive card → text on any API failure
Environment
- Hermes Agent v0.13.0
- Feishu channel via WebSocket
- Python 3.13.5
Problem
When the Feishu (飞书) channel sends AI responses containing markdown tables, the table syntax is displayed as raw source code instead of being rendered as a visual table.
This is because Feishu's
postmessage type withmdtags does not support markdown table syntax. The current workaround (since PR #20275) detects tables and falls back totexttype messages, which prevents blank messages but displays the raw markdown.Reproduction
| col1 | col2 |Root Cause
_build_outbound_payload()ingateway/platforms/feishu.pydetects markdown tables via regex and forcesmsg_type="text", because Feishu'sposttypemdelements render tables as blank.Proposed Solution
Use Feishu Interactive Cards (
msg_type="interactive") with nativetablecomponents, using Card JSON 2.0 ("schema": "2.0"):tablecomponentsmarkdownelements (preserving original markdown — no conversion needed)Feishu Interactive Cards (JSON 2.0) support:
markdownelements: headings, blockquotes, inline code, code blocks, bold, lists, etc.lark_mdcolumn type for rich formatting in table cellsApproach
text(raw source)interactivecard with table componentspostpost(unchanged)texttext(unchanged)Safety measures
```) are not parsedEnvironment