#16123: Feishu card default
channel: feishu
size: XS
Cluster:
Feishu Streaming Enhancements
Pull Request: Default to Card 2.0 for Full Markdown Support
Summary
This PR changes the default renderMode for Feishu outbound messages from "auto" to "card", enabling full markdown rendering for all messages.
Problem
Currently, Feishu uses post message type by default (when renderMode="auto"), which has limited markdown support:
✅ Basic formatting: bold, italic, links
❌ Code blocks with syntax highlighting
❌ Tables
❌ Complex nested lists
❌ Headers
This results in poor user experience when agents send technical content (code snippets, data tables, formatted reports).
Solution
Default to Card 2.0 (interactive message type) which supports full markdown:
✅ Code blocks with syntax highlighting
✅ Tables with alignment
✅ Nested lists
✅ All text formatting
✅ Headers and quotes
Changes
File: extensions/feishu/src/outbound.ts
Before:
sendText: async ({ cfg, to, text, accountId }) => {
const result = await sendMessageFeishu({ cfg, to, text, accountId });
return { channel: "feishu", ...result };
}
After:
sendText: async ({ cfg, to, text, accountId }) => {
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
const renderMode = feishuCfg?.renderMode ?? "card"; // Changed from "auto"
const useRaw = renderMode === "raw";
if (useRaw) {
const result = await sendMessageFeishu({ cfg, to, text, accountId });
return { channel: "feishu", ...result };
} else {
const result = await sendMarkdownCardFeishu({ cfg, to, text, accountId });
return { channel: "feishu", ...result };
}
}
Benefits
Better UX: All markdown renders correctly
No overhead: Same number of API calls
Backward compatible: Users can opt-in to raw mode
Future-proof: Card 2.0 is the recommended format
Testing
Tested on 2026-02-14 with comprehensive markdown examples:
Feature Result Notes
Code blocks ✅ Python/JS/Rust with syntax highlighting
Tables ✅ Multi-column with alignment
Lists ✅ Ordered/unordered/nested/task lists
Text formatting ✅ Bold/italic/strikethrough/inline code
Links ✅ Markdown links render correctly
Headers ✅ H1-H4
Blockquotes ✅ With attribution
Mixed content ✅ Complex reports with all elements
Test Example:
def calculate(x, y):
"""Example function"""
return x + y
Language Year Creator
Python 1991 Guido
Rust 2010 Mozilla
Backward Compatibility
Users who prefer the old behavior can explicitly set:
{
"channels": {
"feishu": {
"renderMode": "raw"
}
}
}
Performance Impact
API calls: No change (1 call per message)
Message size: Minimal increase (~100 bytes for card wrapper)
Latency: No measurable difference
Documentation
Updated configuration documentation needed to reflect new default.
Checklist
Code changes tested
Backward compatibility maintained
Documentation updated (separate PR)
Changelog entry added
Related: Fixes markdown rendering issues reported by users sending technical content via Feishu channel.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Changed default `renderMode` for Feishu outbound messages from `"auto"` to `"card"`, enabling full markdown support (code blocks, tables, nested lists). The implementation correctly applies the new default to both `sendText` and `sendMedia` functions with proper fallback to raw mode when configured.
**Issues found:**
- `PULL_REQUEST_TEMPLATE.md` should not be committed to repo root - appears to be accidentally included
- Local `FeishuConfig` type duplicates existing type from `types.ts`
- Inconsistent default with `reply-dispatcher.ts` which still uses `"auto"`, causing different behavior between outbound adapter and reply dispatcher
- Unused `ClawdbotConfig` import after removing local type definition
<h3>Confidence Score: 3/5</h3>
- This PR has important logic inconsistency that needs resolution before merge
- The code changes are well-implemented and maintain backward compatibility, but there's a critical inconsistency where `reply-dispatcher.ts` still defaults to "auto" while `outbound.ts` defaults to "card". This creates unpredictable behavior where different message paths will render differently. Additionally, the accidentally committed template file and type duplication should be cleaned up.
- Pay close attention to `extensions/feishu/src/reply-dispatcher.ts` (not in this PR) which needs the same default change for consistency
<sub>Last reviewed commit: 37c7f06</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#13917: fix(feishu): card rendering for tables, blockquotes, images, and ou...
by yaoting · 2026-02-11
83.3%
#19027: fix(feishu): keep chunked messages in topic/thread context
by qiangu · 2026-02-17
79.0%
#22598: feat(feishu): support card action callback handler
by yingyixu · 2026-02-21
76.4%
#17863: Fix Feishu card button callback parameters dropped (missing handler)
by Clawborn · 2026-02-16
75.4%
#12755: feat(feishu): render post rich text as markdown
by WilsonLiu95 · 2026-02-09
75.4%
#11084: feat(feishu): implement CardKit streaming card output with typewrit...
by liuhui201069 · 2026-02-07
75.2%
#18529: feat(feishu): add parentId and rootId to inbound context for quote/...
by qiangu · 2026-02-16
73.7%
#21848: feat(feishu): improve agent card experience with single-card stream...
by songshikang0111 · 2026-02-20
73.7%
#9410: docs: add cardkit permissions to Feishu channel setup
by Cassius0924 · 2026-02-05
73.3%
#13211: feat(feishu): skip reply-to in DM conversations
by Vincentwei1021 · 2026-02-10
72.7%