feat(whatsapp): expose forwarded message metadata to agents

- Export extractContextInfo from extract.ts
- Add extractForwardingInfo() function to extract isForwarded and forwardingScore
- Add [forwarded] or [forwarded many times] tag to message body
- Include isForwarded and forwardingScore in WebInboundMessage type
- Pass forwarding metadata in inboundMessage object

Closes: relates to WhatsApp forwarding detection feature request
This commit is contained in:
Rafael Pini 2026-01-28 12:55:02 +00:00
parent da421b9ef7
commit 38c3034cb7
3 changed files with 32 additions and 1 deletions

View File

@ -14,7 +14,7 @@ function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | un
return normalized as proto.IMessage | undefined;
}
function extractContextInfo(message: proto.IMessage | undefined): proto.IContextInfo | undefined {
export function extractContextInfo(message: proto.IMessage | undefined): proto.IContextInfo | undefined {
if (!message) return undefined;
const contentType = getContentType(message);
const candidate = contentType ? (message as Record<string, unknown>)[contentType] : undefined;
@ -46,6 +46,22 @@ function extractContextInfo(message: proto.IMessage | undefined): proto.IContext
return undefined;
}
export interface ForwardingInfo {
isForwarded: boolean;
forwardingScore?: number;
}
export function extractForwardingInfo(rawMessage: proto.IMessage | undefined): ForwardingInfo {
const message = unwrapMessage(rawMessage);
if (!message) return { isForwarded: false };
const contextInfo = extractContextInfo(message);
if (!contextInfo) return { isForwarded: false };
return {
isForwarded: contextInfo.isForwarded ?? false,
forwardingScore: contextInfo.forwardingScore ?? undefined,
};
}
export function extractMentionedJids(rawMessage: proto.IMessage | undefined): string[] | undefined {
const message = unwrapMessage(rawMessage);
if (!message) return undefined;

View File

@ -13,6 +13,7 @@ import { checkInboundAccessControl } from "./access-control.js";
import { isRecentInboundMessage } from "./dedupe.js";
import {
describeReplyContext,
extractForwardingInfo,
extractLocationData,
extractMediaPlaceholder,
extractMentionedJids,
@ -222,6 +223,16 @@ export async function monitorWebInbox(options: {
if (!body) continue;
}
const replyContext = describeReplyContext(msg.message as proto.IMessage | undefined);
const forwardingInfo = extractForwardingInfo(msg.message as proto.IMessage | undefined);
// Add forwarding tag to body if message is forwarded
if (forwardingInfo.isForwarded) {
const forwardTag =
forwardingInfo.forwardingScore && forwardingInfo.forwardingScore >= 5
? "[forwarded many times]"
: "[forwarded]";
body = `${forwardTag} ${body}`;
}
let mediaPath: string | undefined;
let mediaType: string | undefined;
@ -290,6 +301,8 @@ export async function monitorWebInbox(options: {
groupSubject,
groupParticipants,
mentionedJids: mentionedJids ?? undefined,
isForwarded: forwardingInfo.isForwarded,
forwardingScore: forwardingInfo.forwardingScore,
selfJid,
selfE164,
location: location ?? undefined,

View File

@ -29,6 +29,8 @@ export type WebInboundMessage = {
groupSubject?: string;
groupParticipants?: string[];
mentionedJids?: string[];
isForwarded?: boolean;
forwardingScore?: number;
selfJid?: string | null;
selfE164?: string | null;
location?: NormalizedLocation;