fix(feishu): parse interactive card content in quoted messages and merge_forward#34736
fix(feishu): parse interactive card content in quoted messages and merge_forward#34736Daily-AC wants to merge 4 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1bba92d96
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- card structure varies | ||
| const card = parsed as any; |
There was a problem hiding this comment.
Replace no-explicit-any suppression with typed card shape
The repository guideline in AGENTS.md explicitly says not to disable no-explicit-any, but this commit introduces // eslint-disable-next-line @typescript-eslint/no-explicit-any and a cast to any in the new interactive-card parsing path; that removes type guarantees for untrusted message payloads and makes future regressions in this parser harder to catch, so this should be rewritten with a narrow typed interface for the accessed card fields instead of suppressing the rule.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes two related gaps in Feishu interactive card parsing: quoted messages (via The Confidence Score: 3/5
Last reviewed commit: e1bba92 |
| for (const inner of col.elements || []) { | ||
| const t = inner.text?.content || inner.content || ""; | ||
| if (t) texts.push(t); | ||
| } |
There was a problem hiding this comment.
The inner element loop lacks tag filtering. This means it will attempt to extract text?.content or content from any element inside a column — including buttons, images, action elements, and other non-text nodes — potentially leaking unintended content into the output.
The equivalent code in send.ts correctly guards against this by checking innerItem.tag === "markdown" or innerItem.tag === "div" before extraction.
| for (const inner of col.elements || []) { | |
| const t = inner.text?.content || inner.content || ""; | |
| if (t) texts.push(t); | |
| } | |
| for (const inner of col.elements || []) { | |
| if (!inner || typeof inner !== "object") continue; | |
| const innerEl = inner as { tag?: string; content?: string; text?: { content?: string } }; | |
| if (innerEl.tag === "markdown" && innerEl.content) { | |
| texts.push(innerEl.content); | |
| } else if (innerEl.tag === "div") { | |
| const t = innerEl.text?.content || ""; | |
| if (t) texts.push(t); | |
| } | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/feishu/src/bot.ts
Line: 458-461
Comment:
The inner element loop lacks tag filtering. This means it will attempt to extract `text?.content` or `content` from **any** element inside a column — including buttons, images, action elements, and other non-text nodes — potentially leaking unintended content into the output.
The equivalent code in `send.ts` correctly guards against this by checking `innerItem.tag === "markdown"` or `innerItem.tag === "div"` before extraction.
```suggestion
for (const inner of col.elements || []) {
if (!inner || typeof inner !== "object") continue;
const innerEl = inner as { tag?: string; content?: string; text?: { content?: string } };
if (innerEl.tag === "markdown" && innerEl.content) {
texts.push(innerEl.content);
} else if (innerEl.tag === "div") {
const t = innerEl.text?.content || "";
if (t) texts.push(t);
}
}
```
How can I resolve this? If you propose a fix, please make it concise.…rge_forward Enhance parseInteractiveCardContent to extract: - Card header title - body.elements (Card Kit v2 structure) in addition to top-level elements - column_set layout containers with nested text/markdown elements Also add interactive card handling in formatSubMessageContent for merge_forward sub-messages, which previously fell through to the default case and displayed as [interactive]. Fixes openclaw#32712 Fixes openclaw#34571
Only extract text from markdown/div elements inside column_set, skipping buttons, images, and action elements to avoid surfacing unintended content.
92cfbdf to
72a9ac2
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 72a9ac22e3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const elements = parsed.elements || parsed.body?.elements || []; | ||
| const texts: string[] = []; | ||
| for (const el of elements) { |
There was a problem hiding this comment.
Validate card elements before iterating forwarded interactive cards
In the new interactive branch, elements is assigned with parsed.elements || parsed.body?.elements || [] and then iterated directly. If a forwarded card payload has a truthy non-array elements value (for example from malformed or schema-shifted cards), for (const el of elements) throws, the outer catch runs, and we fall back to returning raw JSON content instead of a readable placeholder/card summary. Guarding with Array.isArray here (as done in send.ts) keeps merge-forward formatting resilient.
Useful? React with 👍 / 👎.
|
This pull request has been automatically marked as stale due to inactivity. |
|
Closing due to inactivity. |
Summary
Two related fixes for interactive card content parsing:
1. Quoted message card parsing (fixes #32712)
parseInteractiveCardContentonly checked top-levelelementsarray, missing:header.title.content)body.elementsinstead of top-levelelements)This caused quoted interactive cards to display as
[Interactive Card]instead of showing their content.2. Merge-forward sub-message card parsing (fixes #34571)
formatSubMessageContentinbot.tshad no case forinteractivemessage type, falling through to the default[interactive]placeholder. Added explicit handling using the same enhanced parsing logic.Testing
parseInteractiveCardContent(quoted messages) andformatSubMessageContent(merge_forward) now handle cards