Add WhatsApp reactions support
Summary: Test Plan:
This commit is contained in:
committed by
Peter Steinberger
parent
aa87d6cee8
commit
551a8d5683
@@ -12,6 +12,7 @@ import { createSessionsListTool } from "./tools/sessions-list-tool.js";
|
||||
import { createSessionsSendTool } from "./tools/sessions-send-tool.js";
|
||||
import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js";
|
||||
import { createSlackTool } from "./tools/slack-tool.js";
|
||||
import { createWhatsAppTool } from "./tools/whatsapp-tool.js";
|
||||
|
||||
export function createClawdbotTools(options?: {
|
||||
browserControlUrl?: string;
|
||||
@@ -32,6 +33,7 @@ export function createClawdbotTools(options?: {
|
||||
createCronTool(),
|
||||
createDiscordTool(),
|
||||
createSlackTool(),
|
||||
createWhatsAppTool(),
|
||||
createGatewayTool(),
|
||||
createSessionsListTool({
|
||||
agentSessionKey: options?.agentSessionKey,
|
||||
|
||||
@@ -503,6 +503,12 @@ function shouldIncludeSlackTool(messageProvider?: string): boolean {
|
||||
return normalized === "slack" || normalized.startsWith("slack:");
|
||||
}
|
||||
|
||||
function shouldIncludeWhatsAppTool(messageProvider?: string): boolean {
|
||||
const normalized = normalizeMessageProvider(messageProvider);
|
||||
if (!normalized) return false;
|
||||
return normalized === "whatsapp" || normalized.startsWith("whatsapp:");
|
||||
}
|
||||
|
||||
export function createClawdbotCodingTools(options?: {
|
||||
bash?: BashToolDefaults & ProcessToolDefaults;
|
||||
messageProvider?: string;
|
||||
@@ -562,9 +568,11 @@ export function createClawdbotCodingTools(options?: {
|
||||
];
|
||||
const allowDiscord = shouldIncludeDiscordTool(options?.messageProvider);
|
||||
const allowSlack = shouldIncludeSlackTool(options?.messageProvider);
|
||||
const allowWhatsApp = shouldIncludeWhatsAppTool(options?.messageProvider);
|
||||
const filtered = tools.filter((tool) => {
|
||||
if (tool.name === "discord") return allowDiscord;
|
||||
if (tool.name === "slack") return allowSlack;
|
||||
if (tool.name === "whatsapp") return allowWhatsApp;
|
||||
return true;
|
||||
});
|
||||
const globallyFiltered =
|
||||
|
||||
@@ -231,6 +231,13 @@
|
||||
"memberInfo": { "label": "member", "detailKeys": ["userId"] },
|
||||
"emojiList": { "label": "emoji list" }
|
||||
}
|
||||
},
|
||||
"whatsapp": {
|
||||
"emoji": "💬",
|
||||
"title": "WhatsApp",
|
||||
"actions": {
|
||||
"react": { "label": "react", "detailKeys": ["chatJid", "messageId", "emoji"] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
47
src/agents/tools/whatsapp-actions.ts
Normal file
47
src/agents/tools/whatsapp-actions.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
|
||||
import type {
|
||||
ClawdbotConfig,
|
||||
WhatsAppActionConfig,
|
||||
} from "../../config/config.js";
|
||||
import { isSelfChatMode } from "../../utils.js";
|
||||
import { sendReactionWhatsApp } from "../../web/outbound.js";
|
||||
import { readWebSelfId } from "../../web/session.js";
|
||||
import { jsonResult, readStringParam } from "./common.js";
|
||||
|
||||
type ActionGate = (
|
||||
key: keyof WhatsAppActionConfig,
|
||||
defaultValue?: boolean,
|
||||
) => boolean;
|
||||
|
||||
export async function handleWhatsAppAction(
|
||||
params: Record<string, unknown>,
|
||||
cfg: ClawdbotConfig,
|
||||
): Promise<AgentToolResult<unknown>> {
|
||||
const action = readStringParam(params, "action", { required: true });
|
||||
const isActionEnabled: ActionGate = (key, defaultValue = true) => {
|
||||
const value = cfg.whatsapp?.actions?.[key];
|
||||
if (value === undefined) return defaultValue;
|
||||
return value !== false;
|
||||
};
|
||||
|
||||
if (action === "react") {
|
||||
if (!isActionEnabled("reactions")) {
|
||||
throw new Error("WhatsApp reactions are disabled.");
|
||||
}
|
||||
const chatJid = readStringParam(params, "chatJid", { required: true });
|
||||
const messageId = readStringParam(params, "messageId", { required: true });
|
||||
const emoji = readStringParam(params, "emoji", { required: true });
|
||||
const participant = readStringParam(params, "participant");
|
||||
const selfE164 = readWebSelfId().e164;
|
||||
const fromMe = isSelfChatMode(selfE164, cfg.whatsapp?.allowFrom);
|
||||
await sendReactionWhatsApp(chatJid, messageId, emoji, {
|
||||
verbose: false,
|
||||
fromMe,
|
||||
participant: participant ?? undefined,
|
||||
});
|
||||
return jsonResult({ ok: true });
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported WhatsApp action: ${action}`);
|
||||
}
|
||||
11
src/agents/tools/whatsapp-schema.ts
Normal file
11
src/agents/tools/whatsapp-schema.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
|
||||
export const WhatsAppToolSchema = Type.Union([
|
||||
Type.Object({
|
||||
action: Type.Literal("react"),
|
||||
chatJid: Type.String(),
|
||||
messageId: Type.String(),
|
||||
emoji: Type.String(),
|
||||
participant: Type.Optional(Type.String()),
|
||||
}),
|
||||
]);
|
||||
18
src/agents/tools/whatsapp-tool.ts
Normal file
18
src/agents/tools/whatsapp-tool.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import type { AnyAgentTool } from "./common.js";
|
||||
import { handleWhatsAppAction } from "./whatsapp-actions.js";
|
||||
import { WhatsAppToolSchema } from "./whatsapp-schema.js";
|
||||
|
||||
export function createWhatsAppTool(): AnyAgentTool {
|
||||
return {
|
||||
label: "WhatsApp",
|
||||
name: "whatsapp",
|
||||
description: "Manage WhatsApp reactions.",
|
||||
parameters: WhatsAppToolSchema,
|
||||
execute: async (_toolCallId, args) => {
|
||||
const params = args as Record<string, unknown>;
|
||||
const cfg = loadConfig();
|
||||
return await handleWhatsAppAction(params, cfg);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user