fix(send-media): dedup sendWeixinMediaFile within 5s window (#74)#90
Open
draix wants to merge 1 commit into
Open
fix(send-media): dedup sendWeixinMediaFile within 5s window (#74)#90draix wants to merge 1 commit into
draix wants to merge 1 commit into
Conversation
When the OpenClaw core delivery layer re-parses a MEDIA: directive from an
agent's text payload AND simultaneously honors an explicit `media` field
passed to the message tool, both code paths reach this plugin. The result
is two sendWeixinMediaFile calls for the same (to, filePath) pair within a
few seconds — recipients see duplicate images / files (and the second
upload uses a fresh filekey, so it's not a CDN cache hit).
Until the upstream is fixed, add a plugin-side dedup keyed on
`${to}::${filePath}` with a 5 second window. Repeat invocations
short-circuit and return the previous messageId without re-uploading. The
map is bounded: once it grows past 100 entries we drop anything older than
60 seconds.
Tests cover: same-key within/outside window, cross-key independence
(different recipients or filePaths), file-attachment branch, and GC
bounding.
Refs: openclaw/openclaw#61535 — the dual condition (text dropped) tracks
the same upstream bug from the other direction.
Fixes Tencent#74
Re-Ch-X
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #74 —
sendWeixinMediaFilewas being dispatched twice for the same(to, filePath)pair within ~4 seconds, so recipients received the same image / file twice.This PR adds a plugin-side 5 second in-memory dedup keyed on
${to}::${filePath}. A second invocation landing inside the window short-circuits and returns the previousmessageIdwithout re-uploading.Root cause (upstream)
The OpenClaw core delivery layer re-parses
MEDIA:directives out of agent text payloads. When an agent'smessagetool call carries both surrounding text and an explicitmediafield, the explicit and the parsed paths both reach the plugin'ssendWeixinMediaFile, producing two uploads with two distinctfilekeyvalues.The proper fix lives in core (see openclaw/openclaw#61535 for the mirror condition where the text portion is dropped instead). This PR is the plugin-side defense — the plugin is the last line of defense and can't trust upstream not to call it twice.
Behavior
messagecall with text +mediamediapaths to same recipientmediapath to two recipients(to, filePath)more than 5s apartReproduction (from the issue)
A single
messagetool call:{"action":"send","message":"喏 👇","target":"...@im.wechat","media":"/home/node/.openclaw/media/tool-image-generation/image-1---75cc94db.jpg"}Produces two distinct uploads in the log:
With this PR, the second
sendWeixinMediaFile(≤5 s later, same(to, filePath)) is short-circuited:Implementation
Map<string, { ts: number; messageId: string }>keyed by${to}::${filePath}.DEDUP_WINDOW_MS = 5000.__resetSendMediaDedupForTestsand__sendMediaDedupSizeForTestsexports for assertions; production code does not depend on them.Tests
src/messaging/send-media.test.tsadds 6 new tests (now 12 total in this file). All pass; typecheck is clean.messageIdfilePathvalues to the same recipient both go throughfilePathto different recipients both go throughThe unrelated
pairing.test.ts > uses withFileLockfailure exists onmainalready — it's not introduced by this PR.cc/ maintainers — happy to iterate on logging level, window size, or convert the warn to a counter/metric if you have telemetry preferences.