feat: Add WhatsApp poll support (#248)
Implements issue #123 - WhatsApp Poll Support ## Gateway Protocol - Add `poll` RPC method with params: to, question, options (2-12), selectableCount ## ActiveWebListener - Add `sendPoll(to, poll)` method to interface - Implementation uses Baileys poll message type ## CLI Command - `clawdbot poll --to <jid> -q <question> -o <opt1> -o <opt2> [-s count]` - Supports --dry-run, --json, --verbose flags - Validates 2-12 options ## Changes - src/gateway/protocol/schema.ts: Add PollParamsSchema - src/gateway/protocol/index.ts: Export validator and types - src/web/active-listener.ts: Add sendPoll to interface - src/web/inbound.ts: Implement sendPoll using Baileys - src/web/outbound.ts: Add sendPollWhatsApp function - src/gateway/server-methods/send.ts: Add poll handler - src/commands/poll.ts: New CLI command - src/cli/program.ts: Register poll command Closes #123
This commit is contained in:
@@ -2,6 +2,12 @@ export type ActiveWebSendOptions = {
|
||||
gifPlayback?: boolean;
|
||||
};
|
||||
|
||||
export type PollOptions = {
|
||||
question: string;
|
||||
options: string[];
|
||||
selectableCount?: number;
|
||||
};
|
||||
|
||||
export type ActiveWebListener = {
|
||||
sendMessage: (
|
||||
to: string,
|
||||
@@ -10,6 +16,7 @@ export type ActiveWebListener = {
|
||||
mediaType?: string,
|
||||
options?: ActiveWebSendOptions,
|
||||
) => Promise<{ messageId: string }>;
|
||||
sendPoll: (to: string, poll: PollOptions) => Promise<{ messageId: string }>;
|
||||
sendComposingTo: (to: string) => Promise<void>;
|
||||
close?: () => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -464,6 +464,24 @@ export async function monitorWebInbox(options: {
|
||||
const jid = toWhatsappJid(to);
|
||||
await sock.sendPresenceUpdate("composing", jid);
|
||||
},
|
||||
/**
|
||||
* Send a poll message through this connection's socket.
|
||||
* Used by IPC to create WhatsApp polls in groups or chats.
|
||||
*/
|
||||
sendPoll: async (
|
||||
to: string,
|
||||
poll: { question: string; options: string[]; selectableCount?: number },
|
||||
): Promise<{ messageId: string }> => {
|
||||
const jid = toWhatsappJid(to);
|
||||
const result = await sock.sendMessage(jid, {
|
||||
poll: {
|
||||
name: poll.question,
|
||||
values: poll.options,
|
||||
selectableCount: poll.selectableCount ?? 1,
|
||||
},
|
||||
});
|
||||
return { messageId: result?.key?.id ?? "unknown" };
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createSubsystemLogger, getChildLogger } from "../logging.js";
|
||||
import { toWhatsappJid } from "../utils.js";
|
||||
import {
|
||||
type ActiveWebSendOptions,
|
||||
type PollOptions,
|
||||
getActiveWebListener,
|
||||
} from "./active-listener.js";
|
||||
import { loadWebMedia } from "./media.js";
|
||||
@@ -85,3 +86,44 @@ export async function sendMessageWhatsApp(
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendPollWhatsApp(
|
||||
to: string,
|
||||
poll: PollOptions,
|
||||
options: { verbose: boolean },
|
||||
): Promise<{ messageId: string; toJid: string }> {
|
||||
const correlationId = randomUUID();
|
||||
const startedAt = Date.now();
|
||||
const active = getActiveWebListener();
|
||||
if (!active) {
|
||||
throw new Error(
|
||||
"No active gateway listener. Start the gateway before sending WhatsApp polls.",
|
||||
);
|
||||
}
|
||||
const logger = getChildLogger({
|
||||
module: "web-outbound",
|
||||
correlationId,
|
||||
to,
|
||||
});
|
||||
try {
|
||||
const jid = toWhatsappJid(to);
|
||||
outboundLog.info(`Sending poll -> ${jid}: "${poll.question}"`);
|
||||
logger.info(
|
||||
{ jid, question: poll.question, optionCount: poll.options.length },
|
||||
"sending poll",
|
||||
);
|
||||
const result = await active.sendPoll(to, poll);
|
||||
const messageId =
|
||||
(result as { messageId?: string })?.messageId ?? "unknown";
|
||||
const durationMs = Date.now() - startedAt;
|
||||
outboundLog.info(`Sent poll ${messageId} -> ${jid} (${durationMs}ms)`);
|
||||
logger.info({ jid, messageId }, "sent poll");
|
||||
return { messageId, toJid: jid };
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
{ err: String(err), to, question: poll.question },
|
||||
"failed to send poll via web session",
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user