openclaw - 💡(How to fix) Fix Telegram extension: surface forward_from / via_bot / reply_to_message on MessageReceivedHookEvent [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#71638Fetched 2026-04-26 05:10:17
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

The Telegram extension's message/received hook emit drops three high-signal Telegram update fields that exist on the raw Bot API payload and are required for forensic provenance in downstream consumers:

  • forward_from (and forward_from_chat, forward_origin) — original sender if the inbound message is a forward.
  • via_bot — the bot that produced inline content if the message was sent inline-via.
  • reply_to_message — the parent message context for replies.

The SDK type already exposes a generic metadata: Record<string, unknown> escape hatch on MessageReceivedHookContext (dist/plugin-sdk/src/hooks/internal-hooks.d.ts:53). The Telegram emitter does not populate it for the three fields above.

Root Cause

For incident review, accidental PII relay, and social engineering trace, those distinctions are forensically important. We currently ship a deliberately conservative "sender allowlist confirmation only" footer because we cannot truthfully claim provenance. Closing this FR upstream lets us upgrade the footer in-place without changing the bridge's contract.

Code Example

export type MessageReceivedHookEvent = InternalHookEvent & {
      type: "message";
      action: "received";
      context: MessageReceivedHookContext; // includes optional `metadata`
  };

---

fireAndForgetHook(triggerInternalHook(createInternalHookEvent(
    "message", "received", sessionKey,
    toInternalMessageReceivedContext({
      from, to, content, timestamp, channelId, accountId,
      conversationId, messageId, senderId, senderName, senderUsername,
      provider, surface, threadId, originatingChannel, originatingTo,
      isGroup, groupId
      // no forward / viaBot / replyTo passthrough
    })
  )), "telegram: ...");

---

{
  // existing fields unchanged
  "metadata": {
    "forward": {
      "from": {                  // when msg.forward_from
        "id": 12345,
        "isBot": false,
        "username": "alice",
        "firstName": "Alice"
      },
      "fromChat": {              // when msg.forward_from_chat
        "id": -1001234,
        "type": "channel",
        "title": "Some Channel",
        "username": "somechannel"
      },
      "origin": { /* msg.forward_origin verbatim, Bot API ≥6.4 */ },
      "date": 1714000000,        // msg.forward_date
      "messageId": "789",        // msg.forward_from_message_id when present
      "signature": "Editor Name",// msg.forward_signature when present
      "senderName": "Anon Name"  // msg.forward_sender_name when present
    },
    "viaBot": {                  // when msg.via_bot
      "id": 67890,
      "username": "InlineBot",
      "firstName": "Inline",
      "isBot": true
    },
    "replyTo": {                 // when msg.reply_to_message
      "messageId": "456",
      "chatId": "-1001234",
      "fromId": "111",
      "fromUsername": "bob",
      "text": "first 256 chars of parent text or caption",
      "isForumTopicCreated": false
    }
  }
}
RAW_BUFFERClick to expand / collapse

OpenClaw FR — Surface forward_from, via_bot, reply_to_message in MessageReceivedHookEvent (Telegram)

Filed by: MRQ Intelligence (CISO / Wave 6 Telegram bridge) Tracking ticket: MRQ-internal MRQA-174 OpenClaw version verified against: [email protected]

Summary

The Telegram extension's message/received hook emit drops three high-signal Telegram update fields that exist on the raw Bot API payload and are required for forensic provenance in downstream consumers:

  • forward_from (and forward_from_chat, forward_origin) — original sender if the inbound message is a forward.
  • via_bot — the bot that produced inline content if the message was sent inline-via.
  • reply_to_message — the parent message context for replies.

The SDK type already exposes a generic metadata: Record<string, unknown> escape hatch on MessageReceivedHookContext (dist/plugin-sdk/src/hooks/internal-hooks.d.ts:53). The Telegram emitter does not populate it for the three fields above.

Evidence

  • Hook type: dist/plugin-sdk/src/hooks/internal-hooks.d.ts:55
    export type MessageReceivedHookEvent = InternalHookEvent & {
        type: "message";
        action: "received";
        context: MessageReceivedHookContext; // includes optional `metadata`
    };
  • Emit site (one of several): dist/extensions/telegram/bot-Ch7__EHu.js:3007
    fireAndForgetHook(triggerInternalHook(createInternalHookEvent(
      "message", "received", sessionKey,
      toInternalMessageReceivedContext({
        from, to, content, timestamp, channelId, accountId,
        conversationId, messageId, senderId, senderName, senderUsername,
        provider, surface, threadId, originatingChannel, originatingTo,
        isGroup, groupId
        // no forward / viaBot / replyTo passthrough
      })
    )), "telegram: ...");
  • The bot already reads msg.reply_to_message elsewhere in the same module (e.g. lines 604, 1853, 2964, 3656) for routing/forum logic, so the data is in scope at the emit boundary.

Proposed change (additive, opt-in)

Populate metadata on MessageReceivedHookContext from the Telegram emitter when the corresponding fields are present on the raw msg:

{
  // existing fields unchanged
  "metadata": {
    "forward": {
      "from": {                  // when msg.forward_from
        "id": 12345,
        "isBot": false,
        "username": "alice",
        "firstName": "Alice"
      },
      "fromChat": {              // when msg.forward_from_chat
        "id": -1001234,
        "type": "channel",
        "title": "Some Channel",
        "username": "somechannel"
      },
      "origin": { /* msg.forward_origin verbatim, Bot API ≥6.4 */ },
      "date": 1714000000,        // msg.forward_date
      "messageId": "789",        // msg.forward_from_message_id when present
      "signature": "Editor Name",// msg.forward_signature when present
      "senderName": "Anon Name"  // msg.forward_sender_name when present
    },
    "viaBot": {                  // when msg.via_bot
      "id": 67890,
      "username": "InlineBot",
      "firstName": "Inline",
      "isBot": true
    },
    "replyTo": {                 // when msg.reply_to_message
      "messageId": "456",
      "chatId": "-1001234",
      "fromId": "111",
      "fromUsername": "bob",
      "text": "first 256 chars of parent text or caption",
      "isForumTopicCreated": false
    }
  }
}

Naming: camelCase to match the rest of the SDK surface. Raw Bot API names preserved one level down where they map cleanly (e.g. metadata.forward.origin is forward_origin verbatim).

Truncation: replyTo.text capped (suggested 256 chars) so the hook payload stays bounded; full parent message remains fetchable via Bot API by consumers that need it.

Backwards compatibility

  • Pure additive on the metadata field already declared on MessageReceivedHookContext.
  • No existing field is renamed, removed, or re-typed.
  • Consumers that ignore metadata are unaffected.
  • No new permission scopes or Bot API calls — all data is already on the inbound update.

Apply at every emit site

The change must be made consistently at all createInternalHookEvent("message", "received", …) call sites in the Telegram extension (bot DM, group, mention-skip, forum-topic). The current bundle has at least one such site at bot-Ch7__EHu.js:3007; please audit the source for the full set.

Use case

We operate a Telegram → Paperclip bridge that writes a source-of-origin footer to every ticket created from inbound Telegram messages. Without forward / via-bot / reply context, the footer cannot disambiguate:

  • a message authored by an allowlisted operator vs. one they forwarded from a third party,
  • a reply tied to a specific upstream message vs. a fresh prompt,
  • a message produced via an inline bot vs. directly composed.

For incident review, accidental PII relay, and social engineering trace, those distinctions are forensically important. We currently ship a deliberately conservative "sender allowlist confirmation only" footer because we cannot truthfully claim provenance. Closing this FR upstream lets us upgrade the footer in-place without changing the bridge's contract.

Out of scope

  • Image / audio / sticker forensic context — separate FR if needed.
  • Same fields on MessageSent / MessagePreprocessed events — happy to file follow-ups if the maintainers want symmetry; flagging here to avoid expanding scope of this FR.

Acceptance (from the consumer side)

  • MessageReceivedHookEvent.context.metadata.forward populated when msg.forward_from* / msg.forward_origin is set on the inbound update.
  • MessageReceivedHookEvent.context.metadata.viaBot populated when msg.via_bot is set.
  • MessageReceivedHookEvent.context.metadata.replyTo populated when msg.reply_to_message is set.
  • Behavior unchanged when none of those fields are present on the inbound update.

Happy to provide a PR if the maintainers prefer that route — please advise.

extent analysis

TL;DR

Populate the metadata field in MessageReceivedHookContext with forward_from, via_bot, and reply_to_message fields from the raw Telegram Bot API payload.

Guidance

  • Review the createInternalHookEvent call sites in the Telegram extension to ensure the metadata field is populated consistently.
  • Update the toInternalMessageReceivedContext function to include the forward_from, via_bot, and reply_to_message fields in the metadata object.
  • Verify that the metadata field is correctly populated by checking the MessageReceivedHookEvent payload.
  • Test the updated code to ensure that the metadata field is correctly populated for different types of incoming messages (e.g. forwarded messages, replies, inline bot messages).

Example

const metadata = {
  forward: {
    from: msg.forward_from,
    fromChat: msg.forward_from_chat,
    origin: msg.forward_origin,
    // ...
  },
  viaBot: msg.via_bot,
  replyTo: msg.reply_to_message,
};

const context = toInternalMessageReceivedContext({
  // ...
  metadata,
});

Notes

The proposed change is additive and does not break backwards compatibility, as it only adds new fields to the existing metadata object. However, it is essential to test the updated code thoroughly to ensure that the new fields are correctly populated and do not introduce any issues.

Recommendation

Apply the proposed change to populate the metadata field with the required fields, as it provides valuable forensic context for incoming messages and enhances the functionality of the Telegram bridge.

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

openclaw - 💡(How to fix) Fix Telegram extension: surface forward_from / via_bot / reply_to_message on MessageReceivedHookEvent [1 participants]