Skip to content

fix(actions): send media after card instead of silently dropping it#297

Open
panpeter2024 wants to merge 1 commit intolarksuite:mainfrom
panpeter2024:fix/card-media-conflict
Open

fix(actions): send media after card instead of silently dropping it#297
panpeter2024 wants to merge 1 commit intolarksuite:mainfrom
panpeter2024:fix/card-media-conflict

Conversation

@panpeter2024
Copy link
Copy Markdown

Summary

  • Fix deliverMessage to send both card and media when both are present, instead of silently dropping the media file

Problem

When using the message tool's send action with both a card and a filePath/media parameter, the media file is silently dropped. The deliverMessage function in actions.ts sends only the card and returns immediately, never reaching the media delivery path.

Before (broken):

Card exists? → Send card → return (media silently lost)

After (fixed):

Card + media? → Send card → Send media → return
Card only? → Send card → return
Media only? → Send media → return

This follows the same pattern already used by reply-dispatcher.ts (line 297-361) and outbound.ts (line 215-238), where card and media are sent as separate messages.

Root cause

In deliverMessage (src/messaging/outbound/actions.ts), the card path had an early return that prevented media from ever being sent:

// Card path — immediately returns, media never reached
if (card) {
    const result = await sendCardLark({ ...sendCtx, card });
    return jsonResult({ ... }); // ← early return drops media
}

// Media path — unreachable when card is present
if (mediaUrl) {
    return await deliverMedia(cfg, sp, accountId, mediaLocalRoots);
}

Fix

Added a card && mediaUrl branch that sends card first, then delivers media:

// Card + media path: send card first, then media separately
if (card && mediaUrl) {
    const cardResult = await sendCardLark({ ...sendCtx, card });
    const mediaResult = await deliverMedia(cfg, sp, accountId, mediaLocalRoots);
    return mediaResult;
}

Test plan

  • tsc --noEmit passes
  • All existing tests pass (4 files, 12 tests)
  • Manual: send message with card + filePath → both card and image delivered
  • Manual: send message with card only → card delivered (unchanged)
  • Manual: send message with filePath only → image delivered (unchanged)

Ref: openclaw/openclaw#55091

Made with Cursor

When both card and mediaUrl are present in a send action, deliverMessage
only sent the card and returned immediately, silently discarding the
media file. This caused image files to be lost when sent alongside
interactive cards.

Follow the same pattern as reply-dispatcher.ts: send the card first,
then deliver media as a separate message.

Ref: openclaw/openclaw#55091
Made-with: Cursor
Copy link
Copy Markdown
Collaborator

@HanShaoshuai-k HanShaoshuai-k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I took a closer look at the code and related context, and I think the current card/media mutual exclusion in deliverMessage is intentional rather than a gap:

  1. payloadType is computed as card ? 'card' : mediaUrl ? 'media' : 'text' — modeling the three as mutually exclusive types.
  2. The #288 fix (treating empty {} as undefined) was specifically designed to let routing fall through to the media branch correctly, which confirms the mutual-exclusion model.
  3. sendCardLark's error message explicitly recommends: "If you need images, send them as separate media messages, not inside cards."
  4. messageToolHints makes no mention of card + media combination.

In practice, an LLM agent almost never fills both card and filePath/media in a single tool call. Other channel plugins in the openclaw core repo don't support this combination either — Slack even rejects it explicitly with "Slack send does not support blocks with mediaUrl".

If we do want to handle the edge case where an agent mistakenly passes both, I'd suggest explicitly rejecting with a clear error (consistent with Slack's approach) rather than silently splitting into two messages — that way the agent learns to make separate calls.

@HanShaoshuai-k HanShaoshuai-k added feature request New feature or request changes requested Need do changes labels Mar 30, 2026
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Peter seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes requested Need do changes feature request New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants