openclaw - ✅(Solved) Fix [Feishu] Card streaming creates duplicate card on every response (counts.final=2) [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#62059Fetched 2026-04-08 03:09:34
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
cross-referenced ×1

Every response dispatch creates two streaming card messages in Feishu DMs. The first card receives the full streamed content, and a second identical card (without streaming content) is created ~1 second later.

Root Cause

Traced through the codebase:

  1. In monitor-BFekcwtJ.js, the createFeishuReplyDispatcher deliver callback calls startStreaming() on first block delivery (creates card #1), then calls closeStreaming() on final delivery (closes card #1 via PATCH to /cardkit/v1/cards/{cardId}/settings).

  2. However, counts.final consistently shows 2 in dispatch logs:

feishu[default]: dispatch complete (queuedFinal=false, replies=2)
  1. In dispatch-CYHzwBjK.js, queuedCounts.final increments per sendFinalReply() call. A count of 2 means sendFinalReply() is called twice for a single response.

  2. The first sendFinalReply call closes the streaming card. The second call hits startStreaming() after closeStreaming() has nulled streamingStartPromise, so the guard if (streaming) return fails, and a second streaming card is created and immediately closed.

Fix Action

Workaround

None clean. Using renderMode: "auto" still produces 2 messages (streaming card + fallback text). Only disabling card streaming entirely avoids the duplicate.

PR fix notes

PR #62572: fix(feishu): tighten ACP block visibility fallback behavior

Description (problem / solution / changelog)

Summary

  • add a Feishu ACP visibility override for streamed card-path block text
  • pass cfg and resolved accountId into ACP visibility hook callbacks
  • keep terminal fallback enabled for direct Feishu block delivery to avoid no-reply outcomes

Verification

  • pnpm test src/auto-reply/reply/dispatch-acp-delivery.test.ts src/auto-reply/reply/dispatch-acp.test.ts
  • pnpm test extensions/feishu/src/channel.test.ts
  • pnpm check

Notes

  • Related #62059
  • This is scoped to ACP visibility/fallback behavior and remains a draft-level bugfix pending live Feishu confirmation.

Linked Issue/PR

  • Fixes #62059

Changed files

  • extensions/feishu/src/channel.test.ts (modified, +36/-0)
  • extensions/feishu/src/channel.ts (modified, +26/-0)
  • src/auto-reply/reply/dispatch-acp-delivery.test.ts (modified, +107/-3)
  • src/auto-reply/reply/dispatch-acp-delivery.ts (modified, +13/-0)
  • src/auto-reply/reply/dispatch-acp.test.ts (modified, +37/-1)
  • src/channels/plugins/outbound.types.ts (modified, +4/-0)
  • src/channels/plugins/types.adapters.ts (modified, +0/-1)

Code Example

feishu[default]: dispatch complete (queuedFinal=false, replies=2)

---

card update delta=0ms → cardkit card created (id=7625704855768566742)
card close → cardId=7625704855768566742
card update delta=0ms → cardkit card created (id=7625705023825279638)
card close → cardId=7625705023825279638
RAW_BUFFERClick to expand / collapse

Environment

  • OpenClaw version: 2026.4.5 (3e72c03)
  • Feishu plugin version: 2026.3.8
  • Channel: Feishu (card mode, streaming enabled)
  • Node: v22.22.1, Linux arm64

Description

Every response dispatch creates two streaming card messages in Feishu DMs. The first card receives the full streamed content, and a second identical card (without streaming content) is created ~1 second later.

Root Cause Analysis

Traced through the codebase:

  1. In monitor-BFekcwtJ.js, the createFeishuReplyDispatcher deliver callback calls startStreaming() on first block delivery (creates card #1), then calls closeStreaming() on final delivery (closes card #1 via PATCH to /cardkit/v1/cards/{cardId}/settings).

  2. However, counts.final consistently shows 2 in dispatch logs:

feishu[default]: dispatch complete (queuedFinal=false, replies=2)
  1. In dispatch-CYHzwBjK.js, queuedCounts.final increments per sendFinalReply() call. A count of 2 means sendFinalReply() is called twice for a single response.

  2. The first sendFinalReply call closes the streaming card. The second call hits startStreaming() after closeStreaming() has nulled streamingStartPromise, so the guard if (streaming) return fails, and a second streaming card is created and immediately closed.

Reproduction

  1. Configure Feishu renderer with renderMode: "card", cardName: "claw-default"
  2. Send any message to the bot
  3. Observe two Interactive Card messages appear in the chat

Evidence

From gateway logs (PM2):

card update delta=0ms → cardkit card created (id=7625704855768566742)
card close → cardId=7625704855768566742
card update delta=0ms → cardkit card created (id=7625705023825279638)
card close → cardId=7625705023825279638

Two separate im.message.create calls with different message IDs for a single dispatch.

Expected Behavior

Only one streaming card should be created per response. counts.final should be 1 for normal single-text responses.

Workaround

None clean. Using renderMode: "auto" still produces 2 messages (streaming card + fallback text). Only disabling card streaming entirely avoids the duplicate.

extent analysis

TL;DR

The most likely fix involves modifying the sendFinalReply() call logic to prevent it from being called twice for a single response, thus preventing the creation of a second, identical streaming card.

Guidance

  • Review the dispatch-CYHzwBjK.js file to understand why queuedCounts.final is being incremented twice, leading to two sendFinalReply() calls.
  • Investigate the createFeishuReplyDispatcher deliver callback in monitor-BFekcwtJ.js to see if the startStreaming() and closeStreaming() calls can be optimized to prevent the second card creation.
  • Consider adding a check to prevent sendFinalReply() from being called if a streaming card has already been closed for the same response.
  • Verify the fix by checking the counts.final value in dispatch logs and ensuring only one streaming card is created per response.

Example

No code snippet is provided due to the complexity of the issue and the need for a thorough review of the codebase.

Notes

The provided workaround of disabling card streaming entirely or using renderMode: "auto" does not fully resolve the issue, as it either removes the streaming functionality or still produces duplicate messages. A more targeted fix is required to address the root cause.

Recommendation

Apply a workaround by modifying the sendFinalReply() call logic to prevent duplicate calls, as upgrading to a fixed version is not mentioned in the issue. This approach should help mitigate the issue until a more permanent fix can be implemented.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING