Skip to content

fix(feishu): render markdown tables as Card v2 native table components - #61496

Open
jerryjiao wants to merge 1 commit into
NousResearch:mainfrom
jerryjiao:fix/feishu-markdown-table-card-v2
Open

fix(feishu): render markdown tables as Card v2 native table components#61496
jerryjiao wants to merge 1 commit into
NousResearch:mainfrom
jerryjiao:fix/feishu-markdown-table-card-v2

Conversation

@jerryjiao

Copy link
Copy Markdown

Problem

Feishu (Lark) post-type md elements do not support markdown table syntax. When an agent response contains a GFM markdown table (| col1 | col2 |), the current code downgrades the entire message to plain text — showing raw pipe characters to users instead of a rendered table.

This affects every Hermes user on Feishu/Lark who receives table-formatted responses from agents.

Root Cause

In plugins/platforms/feishu/adapter.py, _build_outbound_payload() detects tables via _MARKDOWN_TABLE_RE but falls back to "text" type payload — which strips all formatting.

Solution

Convert detected markdown tables into Feishu Interactive Card v2 with native table components.

Key format requirements (from official Feishu docs):

Field Wrong (rejected) Correct
rows [[cell, cell]] array {col_0: val} object per row
columns {name, width} only {name, display_name, data_type, width}
card root {config, elements} {schema: "2.0", config, body: {elements}}

Features:

  • ✅ Pure table messages → single table card
  • ✅ Mixed content (text + table + text) → multi-element card with markdown + table
  • ✅ Multiple tables in one message
  • ✅ Graceful fallback to plain text if conversion fails
  • ✅ Strips **bold** markers from table cells

Related PRs

Testing

Tested on Hermes v0.18.2 with real Feishu DM conversations. Tables now render as native interactive cards with proper column alignment and header styling.

Feishu post-type 'md' elements do not support markdown table syntax.
Previously, table content was downgraded to plain text (showing raw
| col | pipes). This patch converts markdown tables to Feishu
Interactive Card (v2) with native table components.

Key format requirements (from official docs):
- rows use object format: {col_0: val} NOT arrays [[cell]]
- columns require display_name + data_type fields
- card requires schema: '2.0' + body.elements wrapper

Supports mixed content (text + table + text) and multiple tables.
Falls back to plain text if conversion fails.
@alt-glitch alt-glitch added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have labels Jul 9, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #12114 (earliest open) — same file (plugins/platforms/feishu/adapter.py) and same approach (render GFM markdown tables as Feishu Card v2 native table components). This enters a saturated cluster; #17006 and #48807 already point to #12114. Related: #17006, #48807.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Comment

Overview

  • Feishu: renders markdown tables as Card v2 native table components
  • Small fix (+160/-4)

Looks Good

  • Clean feature improvement
  • No security concerns

Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing a real Feishu rendering gap: current main still forces detected tables into a plain-text payload at plugins/platforms/feishu/adapter.py:4524-4534.

Problems

  • plugins/platforms/feishu/adapter.py:4528 and the new splitter at PR line 4674 are not fence-aware. A fenced code sample containing a pipe table will be converted into a native table card, changing code-block content. Current main explicitly supports code blocks (plugins/platforms/feishu/adapter.py:1426) and preserves fence-like content in tests/gateway/test_feishu.py:2729.
  • The PR changes only the adapter and adds no regression tests for the new Card v2 path.

Suggested changes

  • Exclude fenced code blocks from table detection/splitting.
  • Add payload-level tests for table, mixed/multiple-table, malformed, and fenced-code inputs.

Automated hermes-sweeper review.

# Feishu post-type 'md' elements do not render markdown tables.
# When a table is detected, convert it to an Interactive Card (v2)
# with native table components so it renders properly in Feishu.
if _MARKDOWN_TABLE_RE.search(content):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex also matches a pipe table inside a fenced code block, then _split_content_with_tables() turns the code sample into a native table. Please make detection fence-aware; current main declares supports_code_blocks = True and has code-block preservation coverage in tests/gateway/test_feishu.py:2729.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages 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 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery 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/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants