Skip to content

feat(bot): use interactive card with markdown for Feishu messages (v2)#1015

Merged
chenjw merged 1 commit intovolcengine:mainfrom
r266-tech:feat/feishu-markdown-v2
Mar 27, 2026
Merged

feat(bot): use interactive card with markdown for Feishu messages (v2)#1015
chenjw merged 1 commit intovolcengine:mainfrom
r266-tech:feat/feishu-markdown-v2

Conversation

@r266-tech
Copy link
Copy Markdown
Contributor

Closes #960

Problem

AI models (LLMs) typically return content in markdown format, but the Feishu channel sends messages using the post message type with plain text elements ({"tag": "text", "text": ...}). This causes markdown syntax like ##, **bold**, and code blocks to display as literal text instead of rendered formatting.

Solution (v2 — fixes from #981 review)

Changed the Feishu message format from post (plain text) to interactive (card with markdown rendering):

  • msg_type: "post""interactive"
  • Content format: Card with {"tag": "markdown", "content": ...} elements instead of {"tag": "text", "text": ...}
  • Card JSON: Direct json.dumps({"elements": ...}) — no extra {"card": ...} wrapper that caused v1 API errors
  • @mentions: Mention prefix on its own line to avoid breaking markdown heading detection in _build_card_elements()
  • @mentions: Only added when reply_to_message_id is present (confirmed reply in group chat)
  • Images: Kept the same {"tag": "img", "img_key": ...} approach within cards
  • Tables/Code: Properly rendered via existing _build_card_elements() which handles markdown tables, headings, and code blocks

Changes

  • bot/vikingbot/channels/feishu.py: Replaced post message building with interactive card building (26 insertions, 35 deletions)

Change Feishu message format from post (plain text) to interactive
card with markdown rendering. Fixes review feedback from volcengine#981.

v2 fixes:
- P0: Remove extra {"card": ...} wrapper from card JSON
- P1: Mention prefix on its own line to avoid breaking heading parsing
- P1: Only add mention prefix when reply_to_message_id is present

Closes volcengine#960
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

@yeshion23333 yeshion23333 self-assigned this Mar 27, 2026
@yeshion23333
Copy link
Copy Markdown
Collaborator

Thanks for your commit!

1) [P1] Interactive card missing config/header may break message sending

File: bot/vikingbot/channels/feishu.py

Location (new): L574-L575

Relevant code:

card_content = json.dumps({"elements": card_elements}, ensure_ascii=False)

Issue:

The interactive card content currently contains only the elements field and is missing config/header. This differs from the official examples; if the server performs strict card schema validation, it can cause message creation to fail. Also, without wide_screen_mode, long text/tables are more likely to be truncated.

Suggestion:

Add config (and header if needed) while keeping elements unchanged, and explicitly enable wide screen mode.

Drop-in example code:

card_payload = {
    "config": {"wide_screen_mode": True},
    "elements": card_elements,
}
card_content = json.dumps(card_payload, ensure_ascii=False)

2) [P1] img element in interactive card misses alt

File: bot/vikingbot/channels/feishu.py

Location (new): L567-L570

Relevant code:

card_elements.append({"tag": "img", "img_key": img["image_key"]})

Issue:

In official card examples, an img component typically includes an alt field (plain_text). The current payload only sends {tag: 'img', img_key: ...}; under stricter validation, this can be considered an incomplete structure and fail to send.

Suggestion:

Add alt (it can be an empty string) to align with the standard card schema.

Drop-in example code:

for img in images:
    card_elements.append(
        {
            "tag": "img",
            "img_key": img["image_key"],
            "alt": {"tag": "plain_text", "content": ""},
        }
    )

3) [P2] Quote the id value in the @mention tag

File: bot/vikingbot/channels/feishu.py

Location (new): L553-L556

Relevant code:

mention_prefix = f"<at id={original_sender_id}></at>"

Issue:

The mention prefix is built as f"<at id={original_sender_id}></at>" and the id value is not quoted. Some rendering paths are stricter and may fail to parse it correctly, causing the mention to not render or not trigger a notification.

Suggestion:

Wrap the id value in double quotes to reduce parsing ambiguity.

Drop-in example code:

mention_prefix = f'<at id="{original_sender_id}"></at>'

@chenjw chenjw merged commit 5a843ae into volcengine:main Mar 27, 2026
5 of 7 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in OpenViking project Mar 27, 2026
r266-tech pushed a commit to r266-tech/OpenViking that referenced this pull request Mar 27, 2026
Follow-up to volcengine#1015. Addresses review comments from yeshion23333:

1. Add config.wide_screen_mode to card payload to prevent text/table
   truncation and align with official card schema
2. Add alt field to img elements for card schema completeness
3. Quote id attribute in @mention tag for parser compatibility
yeshion23333 pushed a commit that referenced this pull request Mar 30, 2026
Follow-up to #1015. Addresses review comments from yeshion23333:

1. Add config.wide_screen_mode to card payload to prevent text/table
   truncation and align with official card schema
2. Add alt field to img elements for card schema completeness
3. Quote id attribute in @mention tag for parser compatibility

Co-authored-by: wzr <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feature]: 建议Bot发送给飞书的消息使用markdown格式

5 participants