openclaw - 💡(How to fix) Fix Expose WhatsApp forwardingScore / isForwarded to plugin inbound_claim hook

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…

The WhatsApp adapter already extracts contextInfo from inbound Baileys envelopes, but the forwarding fields (forwardingScore, isForwarded) are dropped during normalization and never reach plugins. This makes it impossible for a plugin to distinguish a user's own words from a message they forwarded from somewhere else.

Root Cause

The WhatsApp adapter already extracts contextInfo from inbound Baileys envelopes, but the forwarding fields (forwardingScore, isForwarded) are dropped during normalization and never reach plugins. This makes it impossible for a plugin to distinguish a user's own words from a message they forwarded from somewhere else.

Code Example

isForwarded?: boolean;
   forwardingScore?: number;
RAW_BUFFERClick to expand / collapse

Summary

The WhatsApp adapter already extracts contextInfo from inbound Baileys envelopes, but the forwarding fields (forwardingScore, isForwarded) are dropped during normalization and never reach plugins. This makes it impossible for a plugin to distinguish a user's own words from a message they forwarded from somewhere else.

Where the data gets lost

Tracing a WhatsApp inbound through OpenClaw 2026.4.14:

  1. Baileys envelope carries message.extendedTextMessage.contextInfo.forwardingScore (and the deprecated isForwarded boolean).
  2. Adapter normalization in dist/login-D1rNuBKz.js (extractContextInfo around L290) pulls the contextInfo object and reads mentionedJid, quotedMessage, stanzaId, and participant — but not forwarding.
  3. Canonical type CanonicalInboundMessageHookContext in plugin-sdk/src/hooks/message-hook-mappers.d.ts has no forwarding field.
  4. Plugin event builder toPluginInboundClaimEvent in dist/message-hook-mappers-r7wDJRYX.js (L109) constructs a fixed-shape metadata dict. Forwarding is not in it.

So even a plugin that registers inbound_claim or message_received with full access to the event's metadata can't tell whether the text is an original user utterance or a forward.

Proposed change

Three small edits:

  1. Extend CanonicalInboundMessageHookContext with optional fields:
    isForwarded?: boolean;
    forwardingScore?: number;
  2. Populate them in the WhatsApp adapter's normalization path from contextInfo.forwardingScore (treat >= 1 as forwarded).
  3. Pass them through in toPluginInboundClaimEvent and toPluginMessageReceivedEvent (either as first-class fields on the event or as entries in the existing metadata dict — whichever matches the project's convention for adapter-specific signals).

Other channels (Telegram forward_origin, Discord forwarded-message snapshots, Matrix) already have equivalent signals and could opt in later.

Use case

Building a reflective coaching assistant on WhatsApp (Sage). When a user forwards an article or another person's message into the chat to discuss it, the assistant currently reads the content as if the user typed it themselves, which subtly degrades attribution and coaching quality. With the flag exposed, a plugin can prepend [forwarded message] context to the prompt.

Environment

OpenClaw 2026.4.14, @whiskeysockets/baileys bundled in extensions/whatsapp/node_modules/.

extent analysis

TL;DR

To fix the issue, extend the CanonicalInboundMessageHookContext type with optional isForwarded and forwardingScore fields and populate them in the WhatsApp adapter's normalization path.

Guidance

  • Extend the CanonicalInboundMessageHookContext type with optional fields isForwarded and forwardingScore to store forwarding information.
  • Modify the WhatsApp adapter's normalization path to populate these fields from contextInfo.forwardingScore, treating a score of >= 1 as forwarded.
  • Update toPluginInboundClaimEvent and toPluginMessageReceivedEvent to pass the forwarding information to plugins, either as first-class fields or as entries in the metadata dict.
  • Verify the fix by checking that plugins can access the forwarding information in the metadata dict or as separate fields.

Example

// Extend CanonicalInboundMessageHookContext type
interface CanonicalInboundMessageHookContext {
  // ...
  isForwarded?: boolean;
  forwardingScore?: number;
}

// Populate fields in WhatsApp adapter's normalization path
const contextInfo = message.extendedTextMessage.contextInfo;
const isForwarded = contextInfo.forwardingScore >= 1;
const forwardingScore = contextInfo.forwardingScore;

// Pass forwarding information to plugins
const metadata = {
  // ...
  isForwarded,
  forwardingScore,
};

Notes

This fix assumes that the contextInfo.forwardingScore field is always present in the Baileys envelope. If this field is missing or null, additional error handling may be necessary.

Recommendation

Apply the proposed change to extend the CanonicalInboundMessageHookContext type and populate the forwarding fields in the WhatsApp adapter's normalization path, as this will allow plugins to distinguish between original user utterances and forwarded messages.

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