Skip to content

[Bug] Feishu: parseInteractiveCardContent fails on fallback post-format content #60380

@lskun

Description

@lskun

Bug Description

parseInteractiveCardContent() in media-*.js fails to extract text from interactive card messages when the Feishu API returns post-format fallback content instead of card template JSON.

Related: #41609, #48281

Root Cause

When reading a card message via GET /im/v1/messages/{message_id}, Feishu returns body.content in a post-style fallback format (nested arrays with tag: "text" elements), not the original card template format (div/markdown elements).

Current parseInteractiveCardContent() (line ~1019 in media-*.js) only handles:

  • tag === "div" with text.content
  • tag === "markdown" with content

It does not handle:

  • Nested arrays (post fallback format)
  • tag === "text" elements
  • tag === "a" (link) elements
  • tag === "img" elements
  • Card header.title

Reproduction

  1. Bot sends an interactive card via sendCardFeishu (e.g., daily report card with markdown content + image)
  2. User replies to the card and quotes it
  3. Agent tries to read the quoted card via message(action=read, messageId=...)
  4. Result: content: "[Interactive Card]" — all card text is lost

Actual API Response

{
  "body": {
    "content": "{\"title\":\"🤖 clawdbot\",\"elements\":[[{\"tag\":\"img\",\"image_key\":\"img_v3_02ad_...\"},{"tag\":\"text\",\"text\":\"请升级至最新版本客户端,以查看内容\"}]]}"
  },
  "msg_type": "interactive"
}

Note: elements is a nested array [[...]] (post format), not a flat array [...] (card template format). The tag values are "text" and "img", not "div" or "markdown".

Suggested Fix

function parseInteractiveCardContent(parsed) {
  if (!parsed || typeof parsed !== "object") return "[Interactive Card]";
  const texts = [];

  // Extract header title
  if (parsed.header?.title?.content) texts.push(parsed.header.title.content);
  // Extract top-level title (fallback format)
  else if (typeof parsed.title === "string" && parsed.title.trim()) texts.push(parsed.title);

  const elements = Array.isArray(parsed.elements) ? parsed.elements
    : Array.isArray(parsed.body?.elements) ? parsed.body.elements : null;
  if (!elements) return texts.join("\n").trim() || "[Interactive Card]";

  for (const element of elements) {
    // Handle nested arrays (post fallback format)
    if (Array.isArray(element)) {
      for (const sub of element) {
        if (!sub || typeof sub !== "object") continue;
        if (sub.tag === "text" && typeof sub.text === "string" && sub.text.trim()) {
          texts.push(sub.text);
        }
        if (sub.tag === "a" && typeof sub.text === "string") {
          texts.push(sub.text);
        }
      }
      continue;
    }
    if (!element || typeof element !== "object") continue;
    // Existing card template format handlers
    if (element.tag === "div" && typeof element.text?.content === "string") {
      texts.push(element.text.content);
      continue;
    }
    if (element.tag === "markdown" && typeof element.content === "string") {
      texts.push(element.content);
    }
    // Additional: plain_text elements
    if (element.tag === "plain_text" && typeof element.content === "string") {
      texts.push(element.content);
    }
  }
  return texts.join("\n").trim() || "[Interactive Card]";
}

Environment

  • OpenClaw: 2026.4.2
  • Feishu app type: Custom App (企业自建应用)
  • Card sent via: sendCardFeishu / updateCardFeishu
  • Platform: Feishu (not Lark)

Impact

Any agent that needs to read/quote interactive card messages gets empty content. This affects:

  • Reading quoted card messages in group conversations
  • message(action=read) on card messages
  • Thread context when replying to cards

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions