Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions plugins/platforms/feishu/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4526,13 +4526,11 @@ def _is_duplicate(self, message_id: str) -> bool:
# =========================================================================

def _build_outbound_payload(self, content: str) -> tuple[str, str]:
# Feishu post-type 'md' elements do not render markdown tables; sending
# table content as post causes the message to appear blank on the client.
# Force plain text for anything that looks like a markdown table.
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):
# Markdown tables render correctly in post-type 'md' elements as of
# mid-May 2026 (Feishu server-side now parses GFM tables). The earlier
# forced-text-mode fallback (commit 8e18d10) is no longer needed —
# tables now go through the post path with the rest of markdown.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Current main deleted this adapter in 476d8d9ccbee1b36d8fb6f4fabc0081c3e996cd2; the live method is now plugins/platforms/feishu/adapter.py:4524. Please salvage this conditional into that active plugin path so it changes shipped behavior.

if _MARKDOWN_HINT_RE.search(content) or _MARKDOWN_TABLE_RE.search(content):
return "post", _build_markdown_post_payload(content)
text_payload = {"text": content}
return "text", json.dumps(text_payload, ensure_ascii=False)
Expand Down
67 changes: 67 additions & 0 deletions tests/gateway/test_feishu_outbound_routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Regression tests for Feishu outbound payload routing."""

import json
import os
import unittest
from unittest.mock import patch


class TestFeishuOutboundPayloadRouting(unittest.TestCase):
@patch.dict(os.environ, {}, clear=True)
def test_plain_text_routes_to_text(self) -> None:
from gateway.config import PlatformConfig
from plugins.platforms.feishu.adapter import FeishuAdapter

content = "Just a plain line."
adapter = FeishuAdapter(PlatformConfig())

msg_type, payload = adapter._build_outbound_payload(content)

self.assertEqual(msg_type, "text")
self.assertEqual(json.loads(payload), {"text": content})

@patch.dict(os.environ, {}, clear=True)
def test_table_only_content_routes_to_markdown_post(self) -> None:
from gateway.config import PlatformConfig
from plugins.platforms.feishu.adapter import FeishuAdapter

content = "| col1 | col2 |\n|------|------|\n| x | y |"
adapter = FeishuAdapter(PlatformConfig())

msg_type, payload = adapter._build_outbound_payload(content)

self.assertEqual(msg_type, "post")
self.assertEqual(
json.loads(payload),
{
"zh_cn": {
"content": [[{"tag": "md", "text": content}]],
}
},
)

@patch.dict(os.environ, {}, clear=True)
def test_mixed_markdown_and_table_routes_to_markdown_post(self) -> None:
from gateway.config import PlatformConfig
from plugins.platforms.feishu.adapter import FeishuAdapter

content = (
"Summary **below**:\n\n"
"| dimension | status |\n"
"|-----------|--------|\n"
"| **build** | [passing](https://example.com) |\n\n"
"End of summary."
)
adapter = FeishuAdapter(PlatformConfig())

msg_type, payload = adapter._build_outbound_payload(content)

self.assertEqual(msg_type, "post")
self.assertEqual(
json.loads(payload),
{
"zh_cn": {
"content": [[{"tag": "md", "text": content}]],
}
},
)