#21848: feat(feishu): improve agent card experience with single-card streaming and execution timeline
gateway
channel: feishu
size: L
## Summary
- Problem: Currently, Feishu cards do not display the agent’s tool invocation details by default (verboseDefault: off). However, when tool invocation details are enabled (verboseDefault: on/full), a large number of separate message cards are generated, which quickly clutter the chat window.
To help users understand the agent’s execution progress during multi-tool tasks, reduce uncertainty and anxiety, and enable more intuitive debugging and timely interruption, while also preventing tool use messages from overwhelming the chat interface, I designed a new agent card rendering mode that balances both needs.
- Why it matters: Professional users need real-time visibility into tool use progress, while casual users require a more user-friendly card format to improve overall experience.
- What changed:
- Added/used a dedicated Feishu agent-card renderer with serialized update pipeline to enforce single-card updates.
- Added `cardRenderer` config (`default | agent`) under Feishu channel config/account config; `agent` activates aggregated timeline card behavior.
- Implemented strict timeline handling for `tool/block/final` ordering, reasoning inclusion (timeline only), early collapse when final starts, duplicate-final suppression in collapsed timeline
- Restored Chinese UX style details (status titles/icons/colors, `执行过程(Execution process)` panel behavior, tool line text format).
<img width="659" height="285" alt="image" src="https://github.com/user-attachments/assets/03301771-2ca6-4308-9edb-98c74de6ff78" />
- What did NOT change (scope boundary):
- Core verbose semantics (`on`/`full`) were not changed.
- Core OpenClaw reply pipeline/contracts were not changed.
- The existing Feishu plugin rendering modes (card, text, auto) were not changed. A separate toggle was added to enable the new rendering mode (disabled by default).
## Change Type (select all)
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [x] API / contracts
- [x] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Closes #TBD
- Related #TBD
## User-visible / Behavior Changes
- New Feishu config option: `cardRenderer: "default" | "agent"` (top-level and per-account).
- In `renderMode=card` + `cardRenderer=agent`:
- Replies are rendered/updated in a single card (serialized updates).
- Timeline includes ordered `tool/reasoning/block` events.
- `执行过程` panel appears only in final stage and is collapsed immediately when final starts.
- No timeline panel is shown for plain direct replies with no trace content.
- `🧭 New session: ...` is routed to timeline, removed from final body.
- Tool line format:
- with detail: `调用\`toolname\`工具: ...`
- without detail: `调用\`toolname\`工具`
## Security Impact (required)
- New permissions/capabilities? (`Yes/No`) No
- Secrets/tokens handling changed? (`Yes/No`) No
- New/changed network calls? (`Yes/No`) No
- Command/tool execution surface changed? (`Yes/No`) No
- Data access scope changed? (`Yes/No`) No
- If any `Yes`, explain risk + mitigation: N/A
## Repro + Verification
### Environment
- OS: Windows (PowerShell)
- Runtime/container: Node 22.x / pnpm workspace
- Model/provider: N/A (channel rendering path)
- Integration/channel (if any): Feishu extension
- Relevant config (redacted):
- `channels.feishu.renderMode=card`
- `channels.feishu.cardRenderer=agent`
- `agents.defaults.verboseDefault=on|full`
### Steps
1. Enable Feishu `renderMode=card` and `cardRenderer=agent`.
2. Send a prompt that:
- (a) calls tools and then outputs final response,
- (b) outputs direct final response without tools,
- (c) includes session-open system trace (`🧭 New session: ...`).
3. Observe live card updates and final collapsed timeline.
### Expected
- Single card updates throughout.
- Timeline ordered and compact.
- No duplicate final text inside collapsed timeline.
- No `执行过程` panel for plain direct replies without trace/tool/reasoning.
- `🧭 New session: ...` appears in timeline, not final body.
### Actual
- Implemented behavior matches expected in code path.
## Evidence
Attach at least one:
- [ ] Failing test/log before + passing after
- [ ] Trace/log snippets
- [x] Screenshot/recording
- [ ] Perf numbers (if relevant)
## Human Verification (required)
- Automated tests
- Ran the following test suites locally using vitest:
- reply-dispatcher.test.ts → ✅ 2 tests passed (0 failures)
- channel.test.ts → ✅ 1 test passed (0 failures)
- Verified scenarios:
- Code-path verification for single-card serialization and first-card creation lock.
- Timeline parsing/routing for tool/reasoning/block/system-trace.
- Final-collapse timing and duplicate-final trimming logic.
- Edge cases checked:
- Tool line with/without detail.
- No-tool direct response path (no timeline panel).
- Reasoning lines mixed with block text.
## Compatibility / Migration
- Backward compatible? (`Yes/No`) Yes
- Config/env changes? (`Yes/No`) Yes (optional new config)
- Migration needed? (`Yes/No`) No
- If yes, exact upgrade steps: N/A
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly:
- Set `channels.feishu.cardRenderer=default` (or remove it) to return to legacy flow.
- Files/config to restore:
- `extensions/feishu/src/reply-dispatcher.ts`
- `extensions/feishu/src/agent-card.ts`
- `extensions/feishu/src/config-schema.ts`
- `extensions/feishu/src/channel.ts`
- Known bad symptoms reviewers should watch for:
- Multiple cards per single reply in `agent` mode.
- `执行过程` appearing for plain no-tool replies.
- Final content duplicated inside collapsed timeline.
## Risks and Mitigations
- Risk: Timeline parsing from mixed streamed text can misclassify rare edge formats.
- Mitigation: Keep tool classification primarily on dispatcher `info.kind`; regex parsing only for tool line extraction.
- Risk: Serialized update queue may delay very high-frequency updates.
- Mitigation: Batched update scheduler with throttle and latest-card overwrite behavior.
- Risk: Config precedence confusion (top-level vs account-level `cardRenderer`/`streaming`).
- Mitigation: Reuse existing account-merge behavior and document effective config in PR notes.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Introduces a new agent card renderer for Feishu channels that aggregates tool invocations and execution timeline into a single, updating card. The implementation adds `cardRenderer: "default" | "agent"` config option under Feishu channel settings, with the new agent mode providing real-time visibility into tool execution while preventing message spam.
**Key changes:**
- Added new `agent-card.ts` module with timeline tracking, duplicate suppression, and serialized card updates
- Extended `reply-dispatcher.ts` to route messages to agent card renderer when `renderMode=card` and `cardRenderer=agent`
- Added `cardRenderer` config option to schema with account-level override support
- Implemented proper queuing to ensure single-card updates and prevent race conditions
- Timeline includes tool calls, reasoning blocks, and system traces with Chinese UX labels
- Execution process panel appears collapsed only when final content starts (not shown for plain replies)
**Implementation quality:**
- Proper async queue management with `enqueueOp` prevents race conditions
- Backward compatible - disabled by default, requires explicit config
- Clean separation from existing streaming card flow
- Handles edge cases like duplicate final content, missing credentials, and empty timelines
<h3>Confidence Score: 4/5</h3>
- Safe to merge with low risk - well-isolated feature flag
- The implementation is solid with proper error handling, backward compatibility, and clear separation of concerns. Score reflects one minor concern about empty timeline behavior and the CLAUDE.md symlink-to-regular-file conversion, but these are low-impact.
- Check `extensions/feishu/src/agent-card.ts` line 257 for edge case handling of empty timelines
<sub>Last reviewed commit: 682efa8</sub>
<!-- 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
73.7%
#22598: feat(feishu): support card action callback handler
by yingyixu · 2026-02-21
73.2%
#8975: feat(feishu): comprehensive enhancements for Feishu channel
by jiulingyun · 2026-02-04
71.9%
#11084: feat(feishu): implement CardKit streaming card output with typewrit...
by liuhui201069 · 2026-02-07
71.7%
#13917: fix(feishu): card rendering for tables, blockquotes, images, and ou...
by yaoting · 2026-02-11
71.3%
#17863: Fix Feishu card button callback parameters dropped (missing handler)
by Clawborn · 2026-02-16
69.7%
#13970: feat: add Feishu topic auto-threading for message tool
by 4ier · 2026-02-11
69.7%
#17448: ui: make tool cards collapsible with inline expansion
by karimStekelenburg · 2026-02-15
69.0%
#8353: fix(ui): display tool calls during webchat streaming
by MarvinDontPanic · 2026-02-03
68.8%
#9505: fix: Refactor Feishu streaming to prevent truncation and simplify s...
by zhangyi-extra · 2026-02-05
68.7%