#13917: fix(feishu): card rendering for tables, blockquotes, images, and outbound path
channel: feishu
stale
Cluster:
Feishu Streaming Enhancements
## Summary
- **Card image crash fix**: Feishu card API rejects `` with error 230099 because it requires uploaded `image_key`, not raw URLs. Added `processMarkdownImages()` that auto-downloads remote images, uploads to Feishu via `im.image.create` to get `image_key`s, and replaces URLs in the markdown before card rendering. Falls back to link format on failure.
- **Table & blockquote rendering**: Rewrote `buildMarkdownCard()` to parse markdown and convert pipe tables to native Feishu `tag:"table"` elements and blockquotes to visual `▎` bar format, since Feishu card markdown (lark_md) does not support standard markdown tables or `>` syntax.
- **Outbound path card support**: The outbound adapter (used by the `message` tool) always sent via `post` message type, bypassing card rendering. Now detects markdown-rich content and sends via interactive card.
- **Fallback safety**: All card send paths wrapped in try/catch — on failure, automatically falls back to `post` plain text so messages are never silently lost.
## Files changed
| File | Change |
|---|---|
| `extensions/feishu/src/send.ts` | `buildMarkdownCard()` rewrite + `processMarkdownImages()` |
| `extensions/feishu/src/reply-dispatcher.ts` | Image pre-processing + card-to-text fallback |
| `extensions/feishu/src/outbound.ts` | Card rendering for outbound/message-tool path |
## Test plan
- [x] Send interactive card with tables → renders as native Feishu table component
- [x] Send card with blockquotes → renders with `▎` visual bar
- [x] Send card with `` images → images uploaded and displayed (or gracefully degraded to links)
- [x] Card send failure → falls back to post message, no message loss
- [x] Outbound/message-tool path → uses card rendering for markdown-rich content
- [x] Simple text messages → still sent as `post` (no unnecessary card overhead)
Made with [Cursor](https://cursor.com)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR enhances Feishu card rendering by adding support for tables, blockquotes, and images, plus enables card rendering for the outbound/message-tool path. The implementation includes proper fallback mechanisms when card sending fails.
**Key changes:**
- Image processing pipeline that downloads remote images and uploads to Feishu for `image_key` conversion (with fallback to links)
- Markdown parser that converts pipe tables to native Feishu `tag:"table"` elements and blockquotes to visual bar format
- Outbound adapter now detects markdown-rich content and uses card rendering instead of always sending plain text
- Try-catch wrappers ensure messages fall back to plain text on card send failures
**Issues found:**
- String replacement logic for image URLs doesn't escape regex metacharacters, which will fail on markdown containing special characters like `[`, `]`, `(`, `)`
- SSRF vulnerability: arbitrary user-provided image URLs are fetched without validation
- Blockquote regex requires whitespace after `>`, but markdown allows `>text` without space
- Edge case in table parsing where header-only tables without separators may lose content
<h3>Confidence Score: 2/5</h3>
- This PR has critical logic errors in string replacement and a security vulnerability that need to be resolved before merging
- Score reflects multiple critical issues: the string replacement logic for images will fail on common markdown patterns (since matched strings contain regex metacharacters that aren't escaped), there's an SSRF vulnerability in image fetching, and edge cases in parsing logic that could cause data loss
- Pay close attention to `extensions/feishu/src/send.ts` - the image processing and string replacement logic needs fixes before this can safely merge
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16123: Feishu card default
by QiuYi111 · 2026-02-14
83.3%
#12755: feat(feishu): render post rich text as markdown
by WilsonLiu95 · 2026-02-09
80.2%
#11084: feat(feishu): implement CardKit streaming card output with typewrit...
by liuhui201069 · 2026-02-07
79.2%
#9505: fix: Refactor Feishu streaming to prevent truncation and simplify s...
by zhangyi-extra · 2026-02-05
76.0%
#10675: feat(feishu): add audio message support and fix file upload
by YumoeZhung · 2026-02-06
75.9%
#23696: feat(discord): render markdown tables as PNG images
by arismoko · 2026-02-22
75.6%
#22598: feat(feishu): support card action callback handler
by yingyixu · 2026-02-21
75.4%
#19027: fix(feishu): keep chunked messages in topic/thread context
by qiangu · 2026-02-17
74.9%
#14402: fix(feishu): chunk large documents for write/append to avoid API 40...
by lml2468 · 2026-02-12
74.7%
#17863: Fix Feishu card button callback parameters dropped (missing handler)
by Clawborn · 2026-02-16
74.3%