Skip to content

fix(feishu): render Markdown tables via post+md instead of text downgrade - #62161

Closed
yuanchenglu wants to merge 4 commits into
NousResearch:mainfrom
yuanchenglu:fix/feishu-table-post-render
Closed

fix(feishu): render Markdown tables via post+md instead of text downgrade#62161
yuanchenglu wants to merge 4 commits into
NousResearch:mainfrom
yuanchenglu:fix/feishu-table-post-render

Conversation

@yuanchenglu

Copy link
Copy Markdown

Summary

The Feishu outbound payload builder (_build_outbound_payload in plugins/platforms/feishu/adapter.py) was force-routing any message containing a Markdown table to the text message type, based on an outdated assumption that post-type md elements cannot render tables. This caused users to see raw pipe-and-dash markdown syntax (| col | col |) instead of a formatted table in Feishu IM clients.

This assumption is no longer valid. Feishu's post message type with md tag now natively supports GFM (GitHub Flavored Markdown) tables, as documented in the official Feishu API docs:

"如需发送Markdown内容,推荐使用富文本 post 消息中的 md 标签,支持 CommonMark 0.31 + GFM 语法,包括表格、任务列表、删除线、自动链接等能力。"

Changes

  1. _MARKDOWN_HINT_RE — Added (^\|.*\|) so that a pure table content (without other markdown like bold/headings) still matches and routes through the post(md) rendering path instead of falling through to plain text.

  2. _build_outbound_payload — Removed the _MARKDOWN_TABLE_RE force-text guard. Table content now flows through the same post + md element rendering path as all other markdown features.

  3. Outdated comments — Removed stale comments about Feishu not rendering tables in post(md) mode.

Related Issues

Closes: #9549, #52786, #58269, #61643 (and possibly other duplicates)

Testing

Verified on live Feishu IM (feishu.cn, PC + mobile clients):

Scenario Result
2-column simple table ✅ Renders with grid lines, correct alignment
Table + bold + code block + list ✅ All markdown types render, table has grid lines
5-column Chinese content table ✅ Unicode preserved, no garbled headers
8-column x 12-row English table ✅ Horizontal scroll on mobile (expected)
Mixed prose + table + list ✅ Table renders inline, surrounding prose preserved
Code block containing ` ` pipe chars

Risk Assessment

Low. The _MARKDOWN_TABLE_RE regex constant is retained at module level for backward compatibility with any external caller that may reference it (though none exist in the Hermes codebase). The change is entirely within _build_outbound_payload and only affects the outbound message format selection — no inbound parsing, no session logic, no persistence.


概要

Feishu/Lark 消息中的 Markdown 表格一直以原始管道符语法(| 列1 | 列2 |)显示,而不是渲染为带格线的表格。原因是 _build_outbound_payload 检测到表格后强制将消息降级为纯文本类型。这个降级逻辑基于一个过时的假设——飞书 post 消息的 md 标签不支持表格渲染。

修改内容

  1. _MARKDOWN_HINT_RE — 新增 (^\|.*\|) 模式,使纯表格内容也能被识别为 Markdown
  2. _build_outbound_payload — 移除 _MARKDOWN_TABLE_RE 强制纯文本分支,表格内容走正常的 post(md) 渲染路径

测试验证

已在飞书 PC 和移动客户端上验证:表格正确渲染为带格线的原生表格,粗体/代码块/列表等格式正常保留。

相关 Issue

解决 #9549#52786#58269#61643 等 4 个已上报的同一 bug 报告。

…efaults

Introduce a three-tier model resolution chain: global default < group
default (by chat_id) < per-session /model override.  Operators can now
assign a different default model to each Feishu/Telegram/Discord group
without affecting other groups or requiring users to type /model manually.

Changes:
- gateway/config.py: add group_model_defaults: Dict[str, str] field to
  GatewayConfig, with _normalize_group_model_defaults() helper and YAML
  pass-through in load_gateway_config()
- gateway/run.py: check group_model_defaults[chat_id] in
  _resolve_session_agent_runtime() AFTER global model.default but BEFORE
  per-session /model overrides

Usage in config.yaml:
  group_model_defaults:
    oc_869c1d931f317119d8f51f20797b599c: deepseek-v4-flash
    oc_53d22ce34646cebabf06e48ff986ee4c: mistral-large

/ 新增群默认模型覆盖功能,实现三层模型解析链。操作员可为每个群独立设置默认模型,
/ 而不影响其他群或要求用户手动 /model 切换。

@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 identifying the Feishu table routing issue. Current main still forces detected pipe tables to text in plugins/platforms/feishu/adapter.py:4524-4534, so the focused fix is useful.

Problems

  • gateway/config.py:511 and gateway/run.py:2278 add unrelated per-group model routing. This should not be bundled with a Feishu markdown rendering change.
  • plugins/platforms/feishu/adapter.py:155 only recognizes a table row beginning with |. Valid GFM tables without outer pipes still fall through to the plain-text branch.
  • The PR changes no tests. Add a Feishu outbound regression that asserts table-only content is sent as post with an md element.

Suggested changes

  • Re-scope to the Feishu adapter change.
  • Cover optional outer-pipe GFM syntax and add routing tests in tests/gateway/test_feishu.py.

Automated hermes-sweeper review.

Comment thread gateway/config.py
# fresh session exactly as if the reset policy had fired. 0 = disabled.
session_store_max_age_days: int = 90

# Per-group default model overrides: {chat_id: model_name}

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 introduces a separate gateway-wide model-routing feature unrelated to Feishu table rendering. Please split or remove the group_model_defaults changes so this PR remains focused on the reported outbound-format bug.

# ---------------------------------------------------------------------------

_MARKDOWN_HINT_RE = re.compile(
r"(^#{1,6}\s)|(^\s*[-*]\s)|(^\s*\d+\.\s)|(^\s*---+\s*$)|(```)|(`[^`\n]+`)|(\*\*[^*\n].+?\*\*)|(~~[^~\n].+?~~)|(<u>.+?</u>)|(\*[^*\n]+\*)|(\[[^\]]+\]\([^)]+\))|(^\|.*\|)|(^>\s)",

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 only detects table rows beginning with |. GFM also permits Header | Value\n--- | ---\nA | B, which still reaches the plain-text branch. Please recognize optional outer pipes and add a regression test for both forms.

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/feishu Feishu / Lark adapter comp/gateway Gateway runner, session dispatch, delivery sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages P3 Low — cosmetic, nice to have labels Jul 11, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to the saturated Feishu markdown-table cluster: #52790 (earliest-open canonical) and #58019 use the same adapter mechanism; #31056 / #57566 / #53453 use different mechanisms. Not marking this a duplicate because it also bundles an undisclosed, unrelated core-gateway feature (gateway/config.py _normalize_group_model_defaults + gateway/run.py per-group default-model resolution) that is not mentioned in the title/body — please split that out into a focused PR. Maintainer to pick the canonical Feishu-table approach.

@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 11, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing — the table-rendering half of this PR was fixed on main by #68121 (force-text downgrade removed; tables route through post/md, same direction as yours). The per-group model-defaults feature bundled in this PR (gateway/config.py, gateway/run.py) is unrelated to the table fix and deserves its own review — please resubmit it as a focused standalone PR and it will get a proper look. Thanks!

@teknium1 teknium1 closed this Jul 20, 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 comp/plugins Plugin system and bundled plugins 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.

[Feishu] Markdown tables not rendering in Feishu messages

3 participants