feat(whatsapp): add sendReadReceipts config option
Add option to disable automatic read receipts for WhatsApp messages. When set to false, Clawdbot will not mark messages as read (blue ticks). Closes #344 Changes: - Add sendReadReceipts to WhatsAppConfig and WhatsAppAccountConfig types - Add sendReadReceipts to zod schemas for validation - Add sendReadReceipts to ResolvedWhatsAppAccount with fallback chain - Pass sendReadReceipts through to monitorWebInbox - Gate sock.readMessages() call based on config option Default behavior (true) is preserved - only explicitly setting false will disable read receipts.
This commit is contained in:
committed by
Peter Steinberger
parent
44a237b637
commit
7a683a4b62
@@ -14,6 +14,8 @@ export type WhatsAppConfig = {
|
|||||||
capabilities?: string[];
|
capabilities?: string[];
|
||||||
/** Allow channel-initiated config writes (default: true). */
|
/** Allow channel-initiated config writes (default: true). */
|
||||||
configWrites?: boolean;
|
configWrites?: boolean;
|
||||||
|
/** Send read receipts for incoming messages (default true). */
|
||||||
|
sendReadReceipts?: boolean;
|
||||||
/**
|
/**
|
||||||
* Inbound message prefix (WhatsApp only).
|
* Inbound message prefix (WhatsApp only).
|
||||||
* Default: `[{agents.list[].identity.name}]` (or `[clawdbot]`) when allowFrom is empty, else `""`.
|
* Default: `[{agents.list[].identity.name}]` (or `[clawdbot]`) when allowFrom is empty, else `""`.
|
||||||
@@ -84,6 +86,8 @@ export type WhatsAppAccountConfig = {
|
|||||||
configWrites?: boolean;
|
configWrites?: boolean;
|
||||||
/** If false, do not start this WhatsApp account provider. Default: true. */
|
/** If false, do not start this WhatsApp account provider. Default: true. */
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
/** Send read receipts for incoming messages (default true). */
|
||||||
|
sendReadReceipts?: boolean;
|
||||||
/** Inbound message prefix override for this account (WhatsApp only). */
|
/** Inbound message prefix override for this account (WhatsApp only). */
|
||||||
messagePrefix?: string;
|
messagePrefix?: string;
|
||||||
/** Override auth directory (Baileys multi-file auth state). */
|
/** Override auth directory (Baileys multi-file auth state). */
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const WhatsAppAccountSchema = z
|
|||||||
capabilities: z.array(z.string()).optional(),
|
capabilities: z.array(z.string()).optional(),
|
||||||
configWrites: z.boolean().optional(),
|
configWrites: z.boolean().optional(),
|
||||||
enabled: z.boolean().optional(),
|
enabled: z.boolean().optional(),
|
||||||
|
sendReadReceipts: z.boolean().optional(),
|
||||||
messagePrefix: z.string().optional(),
|
messagePrefix: z.string().optional(),
|
||||||
/** Override auth directory for this WhatsApp account (Baileys multi-file auth state). */
|
/** Override auth directory for this WhatsApp account (Baileys multi-file auth state). */
|
||||||
authDir: z.string().optional(),
|
authDir: z.string().optional(),
|
||||||
@@ -62,6 +63,7 @@ export const WhatsAppConfigSchema = z
|
|||||||
accounts: z.record(z.string(), WhatsAppAccountSchema.optional()).optional(),
|
accounts: z.record(z.string(), WhatsAppAccountSchema.optional()).optional(),
|
||||||
capabilities: z.array(z.string()).optional(),
|
capabilities: z.array(z.string()).optional(),
|
||||||
configWrites: z.boolean().optional(),
|
configWrites: z.boolean().optional(),
|
||||||
|
sendReadReceipts: z.boolean().optional(),
|
||||||
dmPolicy: DmPolicySchema.optional().default("pairing"),
|
dmPolicy: DmPolicySchema.optional().default("pairing"),
|
||||||
messagePrefix: z.string().optional(),
|
messagePrefix: z.string().optional(),
|
||||||
selfChatMode: z.boolean().optional(),
|
selfChatMode: z.boolean().optional(),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export type ResolvedWhatsAppAccount = {
|
|||||||
accountId: string;
|
accountId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
sendReadReceipts: boolean;
|
||||||
messagePrefix?: string;
|
messagePrefix?: string;
|
||||||
authDir: string;
|
authDir: string;
|
||||||
isLegacyAuthDir: boolean;
|
isLegacyAuthDir: boolean;
|
||||||
@@ -125,6 +126,7 @@ export function resolveWhatsAppAccount(params: {
|
|||||||
cfg: ClawdbotConfig;
|
cfg: ClawdbotConfig;
|
||||||
accountId?: string | null;
|
accountId?: string | null;
|
||||||
}): ResolvedWhatsAppAccount {
|
}): ResolvedWhatsAppAccount {
|
||||||
|
const rootCfg = params.cfg.channels?.whatsapp;
|
||||||
const accountId = params.accountId?.trim() || resolveDefaultWhatsAppAccountId(params.cfg);
|
const accountId = params.accountId?.trim() || resolveDefaultWhatsAppAccountId(params.cfg);
|
||||||
const accountCfg = resolveAccountConfig(params.cfg, accountId);
|
const accountCfg = resolveAccountConfig(params.cfg, accountId);
|
||||||
const enabled = accountCfg?.enabled !== false;
|
const enabled = accountCfg?.enabled !== false;
|
||||||
@@ -136,22 +138,21 @@ export function resolveWhatsAppAccount(params: {
|
|||||||
accountId,
|
accountId,
|
||||||
name: accountCfg?.name?.trim() || undefined,
|
name: accountCfg?.name?.trim() || undefined,
|
||||||
enabled,
|
enabled,
|
||||||
|
sendReadReceipts: accountCfg?.sendReadReceipts ?? rootCfg?.sendReadReceipts ?? true,
|
||||||
messagePrefix:
|
messagePrefix:
|
||||||
accountCfg?.messagePrefix ??
|
accountCfg?.messagePrefix ?? rootCfg?.messagePrefix ?? params.cfg.messages?.messagePrefix,
|
||||||
params.cfg.channels?.whatsapp?.messagePrefix ??
|
|
||||||
params.cfg.messages?.messagePrefix,
|
|
||||||
authDir,
|
authDir,
|
||||||
isLegacyAuthDir: isLegacy,
|
isLegacyAuthDir: isLegacy,
|
||||||
selfChatMode: accountCfg?.selfChatMode ?? params.cfg.channels?.whatsapp?.selfChatMode,
|
selfChatMode: accountCfg?.selfChatMode ?? rootCfg?.selfChatMode,
|
||||||
dmPolicy: accountCfg?.dmPolicy ?? params.cfg.channels?.whatsapp?.dmPolicy,
|
dmPolicy: accountCfg?.dmPolicy ?? rootCfg?.dmPolicy,
|
||||||
allowFrom: accountCfg?.allowFrom ?? params.cfg.channels?.whatsapp?.allowFrom,
|
allowFrom: accountCfg?.allowFrom ?? rootCfg?.allowFrom,
|
||||||
groupAllowFrom: accountCfg?.groupAllowFrom ?? params.cfg.channels?.whatsapp?.groupAllowFrom,
|
groupAllowFrom: accountCfg?.groupAllowFrom ?? rootCfg?.groupAllowFrom,
|
||||||
groupPolicy: accountCfg?.groupPolicy ?? params.cfg.channels?.whatsapp?.groupPolicy,
|
groupPolicy: accountCfg?.groupPolicy ?? rootCfg?.groupPolicy,
|
||||||
textChunkLimit: accountCfg?.textChunkLimit ?? params.cfg.channels?.whatsapp?.textChunkLimit,
|
textChunkLimit: accountCfg?.textChunkLimit ?? rootCfg?.textChunkLimit,
|
||||||
mediaMaxMb: accountCfg?.mediaMaxMb ?? params.cfg.channels?.whatsapp?.mediaMaxMb,
|
mediaMaxMb: accountCfg?.mediaMaxMb ?? rootCfg?.mediaMaxMb,
|
||||||
blockStreaming: accountCfg?.blockStreaming ?? params.cfg.channels?.whatsapp?.blockStreaming,
|
blockStreaming: accountCfg?.blockStreaming ?? rootCfg?.blockStreaming,
|
||||||
ackReaction: accountCfg?.ackReaction ?? params.cfg.channels?.whatsapp?.ackReaction,
|
ackReaction: accountCfg?.ackReaction ?? rootCfg?.ackReaction,
|
||||||
groups: accountCfg?.groups ?? params.cfg.channels?.whatsapp?.groups,
|
groups: accountCfg?.groups ?? rootCfg?.groups,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ export async function monitorWebChannel(
|
|||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
authDir: account.authDir,
|
authDir: account.authDir,
|
||||||
mediaMaxMb: account.mediaMaxMb,
|
mediaMaxMb: account.mediaMaxMb,
|
||||||
|
sendReadReceipts: account.sendReadReceipts,
|
||||||
onMessage: async (msg: WebInboundMsg) => {
|
onMessage: async (msg: WebInboundMsg) => {
|
||||||
handledMessages += 1;
|
handledMessages += 1;
|
||||||
lastMessageAt = Date.now();
|
lastMessageAt = Date.now();
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export async function monitorWebInbox(options: {
|
|||||||
authDir: string;
|
authDir: string;
|
||||||
onMessage: (msg: WebInboundMessage) => Promise<void>;
|
onMessage: (msg: WebInboundMessage) => Promise<void>;
|
||||||
mediaMaxMb?: number;
|
mediaMaxMb?: number;
|
||||||
|
/** Send read receipts for incoming messages (default true). */
|
||||||
|
sendReadReceipts?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const inboundLogger = getChildLogger({ module: "web-inbound" });
|
const inboundLogger = getChildLogger({ module: "web-inbound" });
|
||||||
const inboundConsoleLog = createSubsystemLogger("gateway/channels/whatsapp").child("inbound");
|
const inboundConsoleLog = createSubsystemLogger("gateway/channels/whatsapp").child("inbound");
|
||||||
@@ -139,7 +141,11 @@ export async function monitorWebInbox(options: {
|
|||||||
});
|
});
|
||||||
if (!access.allowed) continue;
|
if (!access.allowed) continue;
|
||||||
|
|
||||||
if (id && !access.isSelfChat) {
|
if (
|
||||||
|
id &&
|
||||||
|
!access.isSelfChat &&
|
||||||
|
options.sendReadReceipts !== false
|
||||||
|
) {
|
||||||
const participant = msg.key?.participant;
|
const participant = msg.key?.participant;
|
||||||
try {
|
try {
|
||||||
await sock.readMessages([{ remoteJid, id, participant, fromMe: false }]);
|
await sock.readMessages([{ remoteJid, id, participant, fromMe: false }]);
|
||||||
|
|||||||
Reference in New Issue
Block a user