Skip to content

Commit d6569e6

Browse files
hetaoBackendclaude
andauthored
Show Feishu card content inline (#11)
* fix: stabilize forwarded message timestamps * fix lint * Simplify Feishu result cards * fix lint * Rebuild bundled backend before packaging * Fix scheduled_at timezone handling and Feishu card UX * fix lint * Show Feishu card content inline --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 686f741 commit d6569e6

3 files changed

Lines changed: 39 additions & 57 deletions

File tree

channels/feishu_channel.py

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@
6565
• 回复任意结果通知即可继续对话。
6666
"""
6767

68-
FEISHU_RESULT_PREVIEW_LIMIT = 500
69-
FEISHU_INLINE_RESULT_LIMIT = 1200
7068
FEISHU_CARD_MARKDOWN_CHUNK = 7000
7169
FEISHU_FALLBACK_MARKDOWN_LIMIT = 8000
7270

@@ -423,31 +421,10 @@ def _build_notification_card(
423421

424422
def _build_result_elements(self, body_text: str) -> list[dict[str, Any]]:
425423
clean_body = (body_text or "").strip() or "Done."
426-
if len(clean_body) <= FEISHU_INLINE_RESULT_LIMIT:
427-
return [
428-
{
429-
"tag": "markdown",
430-
"content": clean_body,
431-
}
432-
]
433-
434-
panel_elements = [
424+
return [
435425
{"tag": "markdown", "content": chunk}
436426
for chunk in self._chunk_text(clean_body, FEISHU_CARD_MARKDOWN_CHUNK)
437427
]
438-
return [
439-
{
440-
"tag": "collapsible_panel",
441-
"expanded": False,
442-
"header": {
443-
"title": {
444-
"tag": "plain_text",
445-
"content": "展开查看完整结果",
446-
}
447-
},
448-
"elements": panel_elements,
449-
},
450-
]
451428

452429
def _build_legacy_markdown_card(self, content: str) -> dict[str, Any]:
453430
return {

tests/test_feishu_message_rendering.py

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def test_build_failed_card_adds_status_hint(self, mock_feishu_channel):
7676
for element in card["body"]["elements"]
7777
)
7878

79-
def test_build_completed_card_wraps_long_body_in_collapsible_panel(self, mock_feishu_channel):
79+
def test_build_completed_card_keeps_long_body_visible(self, mock_feishu_channel):
8080
task = {
8181
"id": 99,
8282
"title": "Long output task",
@@ -93,10 +93,13 @@ def test_build_completed_card_wraps_long_body_in_collapsible_panel(self, mock_fe
9393
body_text=long_text,
9494
)
9595

96-
assert card["body"]["elements"][0]["tag"] == "collapsible_panel"
97-
assert card["body"]["elements"][0]["elements"][0]["content"] == long_text
96+
assert card["body"]["elements"][0]["tag"] == "markdown"
97+
assert card["body"]["elements"] == [{"tag": "markdown", "content": long_text}]
98+
assert not any(
99+
element.get("tag") == "collapsible_panel" for element in card["body"]["elements"]
100+
)
98101

99-
def test_build_completed_card_expanded_panel_keeps_full_remainder(self, mock_feishu_channel):
102+
def test_build_completed_card_long_body_keeps_full_remainder(self, mock_feishu_channel):
100103
task = {
101104
"id": 100,
102105
"title": "Long output task",
@@ -112,19 +115,15 @@ def test_build_completed_card_expanded_panel_keeps_full_remainder(self, mock_fei
112115
is_completed=True,
113116
body_text=long_text,
114117
)
115-
116-
panel = next(
117-
element
118-
for element in card["body"]["elements"]
119-
if element.get("tag") == "collapsible_panel"
118+
assert card["body"]["elements"][0]["content"].startswith("A" * 20)
119+
assert "".join(element["content"] for element in card["body"]["elements"]) == long_text
120+
assert "truncated" not in "".join(
121+
element["content"] for element in card["body"]["elements"]
120122
)
121-
expanded_text = panel["elements"][0]["content"]
122-
123-
assert expanded_text.startswith("A" * 20)
124-
assert expanded_text.endswith("B" * 20)
125-
assert "truncated" not in expanded_text
126123

127-
def test_build_completed_card_long_body_uses_summary_plus_full_panel(self, mock_feishu_channel):
124+
def test_build_completed_card_long_body_uses_summary_plus_full_content(
125+
self, mock_feishu_channel
126+
):
128127
task = {
129128
"id": 101,
130129
"title": "Long output task",
@@ -142,24 +141,29 @@ def test_build_completed_card_long_body_uses_summary_plus_full_panel(self, mock_
142141
)
143142

144143
assert card["config"]["summary"]["content"] == "Summary line"
145-
assert card["body"]["elements"] == [
146-
{
147-
"tag": "collapsible_panel",
148-
"expanded": False,
149-
"header": {
150-
"title": {
151-
"tag": "plain_text",
152-
"content": "展开查看完整结果",
153-
}
154-
},
155-
"elements": [
156-
{
157-
"tag": "markdown",
158-
"content": long_text,
159-
}
160-
],
161-
}
162-
]
144+
assert card["body"]["elements"] == [{"tag": "markdown", "content": long_text}]
145+
146+
def test_build_completed_card_long_body_has_no_collapsible_panel(self, mock_feishu_channel):
147+
task = {
148+
"id": 102,
149+
"title": "Long output task",
150+
"prompt": "输出一份很长的结果",
151+
"agent": "codex",
152+
"working_dir": "~/workspace/agentforge",
153+
}
154+
long_text = "Intro line\n" + ("B" * 1400)
155+
156+
card = mock_feishu_channel._build_notification_card(
157+
task_id=102,
158+
task=task,
159+
is_completed=True,
160+
body_text=long_text,
161+
)
162+
163+
assert not any(
164+
element.get("tag") == "collapsible_panel" for element in card["body"]["elements"]
165+
)
166+
assert "".join(element["content"] for element in card["body"]["elements"]) == long_text
163167

164168
def test_send_uses_structured_card_and_fallback_content(self, mock_feishu_channel):
165169
task = {

todo.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- [completed] 修复飞书长结果卡片在转发场景下首屏不可读且展开重复预览的问题

0 commit comments

Comments
 (0)