Skip to content
25 changes: 1 addition & 24 deletions channels/feishu_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@
• 回复任意结果通知即可继续对话。
"""

FEISHU_RESULT_PREVIEW_LIMIT = 500
FEISHU_INLINE_RESULT_LIMIT = 1200
FEISHU_CARD_MARKDOWN_CHUNK = 7000
FEISHU_FALLBACK_MARKDOWN_LIMIT = 8000

Expand Down Expand Up @@ -423,31 +421,10 @@ def _build_notification_card(

def _build_result_elements(self, body_text: str) -> list[dict[str, Any]]:
clean_body = (body_text or "").strip() or "Done."
if len(clean_body) <= FEISHU_INLINE_RESULT_LIMIT:
return [
{
"tag": "markdown",
"content": clean_body,
}
]

panel_elements = [
return [
{"tag": "markdown", "content": chunk}
for chunk in self._chunk_text(clean_body, FEISHU_CARD_MARKDOWN_CHUNK)
]
return [
{
"tag": "collapsible_panel",
"expanded": False,
"header": {
"title": {
"tag": "plain_text",
"content": "展开查看完整结果",
}
},
"elements": panel_elements,
},
]

def _build_legacy_markdown_card(self, content: str) -> dict[str, Any]:
return {
Expand Down
70 changes: 37 additions & 33 deletions tests/test_feishu_message_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_build_failed_card_adds_status_hint(self, mock_feishu_channel):
for element in card["body"]["elements"]
)

def test_build_completed_card_wraps_long_body_in_collapsible_panel(self, mock_feishu_channel):
def test_build_completed_card_keeps_long_body_visible(self, mock_feishu_channel):
task = {
"id": 99,
"title": "Long output task",
Expand All @@ -93,10 +93,13 @@ def test_build_completed_card_wraps_long_body_in_collapsible_panel(self, mock_fe
body_text=long_text,
)

assert card["body"]["elements"][0]["tag"] == "collapsible_panel"
assert card["body"]["elements"][0]["elements"][0]["content"] == long_text
assert card["body"]["elements"][0]["tag"] == "markdown"
assert card["body"]["elements"] == [{"tag": "markdown", "content": long_text}]
assert not any(
element.get("tag") == "collapsible_panel" for element in card["body"]["elements"]
)

def test_build_completed_card_expanded_panel_keeps_full_remainder(self, mock_feishu_channel):
def test_build_completed_card_long_body_keeps_full_remainder(self, mock_feishu_channel):
task = {
"id": 100,
"title": "Long output task",
Expand All @@ -112,19 +115,15 @@ def test_build_completed_card_expanded_panel_keeps_full_remainder(self, mock_fei
is_completed=True,
body_text=long_text,
)

panel = next(
element
for element in card["body"]["elements"]
if element.get("tag") == "collapsible_panel"
assert card["body"]["elements"][0]["content"].startswith("A" * 20)
assert "".join(element["content"] for element in card["body"]["elements"]) == long_text
assert "truncated" not in "".join(
element["content"] for element in card["body"]["elements"]
)
expanded_text = panel["elements"][0]["content"]

assert expanded_text.startswith("A" * 20)
assert expanded_text.endswith("B" * 20)
assert "truncated" not in expanded_text

def test_build_completed_card_long_body_uses_summary_plus_full_panel(self, mock_feishu_channel):
def test_build_completed_card_long_body_uses_summary_plus_full_content(
self, mock_feishu_channel
):
task = {
"id": 101,
"title": "Long output task",
Expand All @@ -142,24 +141,29 @@ def test_build_completed_card_long_body_uses_summary_plus_full_panel(self, mock_
)

assert card["config"]["summary"]["content"] == "Summary line"
assert card["body"]["elements"] == [
{
"tag": "collapsible_panel",
"expanded": False,
"header": {
"title": {
"tag": "plain_text",
"content": "展开查看完整结果",
}
},
"elements": [
{
"tag": "markdown",
"content": long_text,
}
],
}
]
assert card["body"]["elements"] == [{"tag": "markdown", "content": long_text}]

def test_build_completed_card_long_body_has_no_collapsible_panel(self, mock_feishu_channel):
task = {
"id": 102,
"title": "Long output task",
"prompt": "输出一份很长的结果",
"agent": "codex",
"working_dir": "~/workspace/agentforge",
}
long_text = "Intro line\n" + ("B" * 1400)

card = mock_feishu_channel._build_notification_card(
task_id=102,
task=task,
is_completed=True,
body_text=long_text,
)

assert not any(
element.get("tag") == "collapsible_panel" for element in card["body"]["elements"]
)
assert "".join(element["content"] for element in card["body"]["elements"]) == long_text

def test_send_uses_structured_card_and_fallback_content(self, mock_feishu_channel):
task = {
Expand Down
1 change: 1 addition & 0 deletions todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [completed] 修复飞书长结果卡片在转发场景下首屏不可读且展开重复预览的问题
Loading