Files
clawdbot/src/agents/tools/discord-actions-messaging.ts
2026-01-04 05:07:44 +01:00

326 lines
11 KiB
TypeScript

import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import type { DiscordActionConfig } from "../../config/config.js";
import {
createThreadDiscord,
deleteMessageDiscord,
editMessageDiscord,
fetchChannelPermissionsDiscord,
fetchReactionsDiscord,
listPinsDiscord,
listThreadsDiscord,
pinMessageDiscord,
reactMessageDiscord,
readMessagesDiscord,
searchMessagesDiscord,
sendMessageDiscord,
sendPollDiscord,
sendStickerDiscord,
unpinMessageDiscord,
} from "../../discord/send.js";
import { jsonResult, readStringArrayParam, readStringParam } from "./common.js";
type ActionGate = (
key: keyof DiscordActionConfig,
defaultValue?: boolean,
) => boolean;
export async function handleDiscordMessagingAction(
action: string,
params: Record<string, unknown>,
isActionEnabled: ActionGate,
): Promise<AgentToolResult<unknown>> {
switch (action) {
case "react": {
if (!isActionEnabled("reactions")) {
throw new Error("Discord reactions are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
const emoji = readStringParam(params, "emoji", { required: true });
await reactMessageDiscord(channelId, messageId, emoji);
return jsonResult({ ok: true });
}
case "reactions": {
if (!isActionEnabled("reactions")) {
throw new Error("Discord reactions are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
const limitRaw = params.limit;
const limit =
typeof limitRaw === "number" && Number.isFinite(limitRaw)
? limitRaw
: undefined;
const reactions = await fetchReactionsDiscord(channelId, messageId, {
limit,
});
return jsonResult({ ok: true, reactions });
}
case "sticker": {
if (!isActionEnabled("stickers")) {
throw new Error("Discord stickers are disabled.");
}
const to = readStringParam(params, "to", { required: true });
const content = readStringParam(params, "content");
const stickerIds = readStringArrayParam(params, "stickerIds", {
required: true,
label: "stickerIds",
});
await sendStickerDiscord(to, stickerIds, { content });
return jsonResult({ ok: true });
}
case "poll": {
if (!isActionEnabled("polls")) {
throw new Error("Discord polls are disabled.");
}
const to = readStringParam(params, "to", { required: true });
const content = readStringParam(params, "content");
const question = readStringParam(params, "question", {
required: true,
});
const answers = readStringArrayParam(params, "answers", {
required: true,
label: "answers",
});
const allowMultiselectRaw = params.allowMultiselect;
const allowMultiselect =
typeof allowMultiselectRaw === "boolean"
? allowMultiselectRaw
: undefined;
const durationRaw = params.durationHours;
const durationHours =
typeof durationRaw === "number" && Number.isFinite(durationRaw)
? durationRaw
: undefined;
await sendPollDiscord(
to,
{ question, answers, allowMultiselect, durationHours },
{ content },
);
return jsonResult({ ok: true });
}
case "permissions": {
if (!isActionEnabled("permissions")) {
throw new Error("Discord permissions are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const permissions = await fetchChannelPermissionsDiscord(channelId);
return jsonResult({ ok: true, permissions });
}
case "readMessages": {
if (!isActionEnabled("messages")) {
throw new Error("Discord message reads are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messages = await readMessagesDiscord(channelId, {
limit:
typeof params.limit === "number" && Number.isFinite(params.limit)
? params.limit
: undefined,
before: readStringParam(params, "before"),
after: readStringParam(params, "after"),
around: readStringParam(params, "around"),
});
return jsonResult({ ok: true, messages });
}
case "sendMessage": {
if (!isActionEnabled("messages")) {
throw new Error("Discord message sends are disabled.");
}
const to = readStringParam(params, "to", { required: true });
const content = readStringParam(params, "content", {
required: true,
});
const mediaUrl = readStringParam(params, "mediaUrl");
const replyTo = readStringParam(params, "replyTo");
const result = await sendMessageDiscord(to, content, {
mediaUrl,
replyTo,
});
return jsonResult({ ok: true, result });
}
case "editMessage": {
if (!isActionEnabled("messages")) {
throw new Error("Discord message edits are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
const content = readStringParam(params, "content", {
required: true,
});
const message = await editMessageDiscord(channelId, messageId, {
content,
});
return jsonResult({ ok: true, message });
}
case "deleteMessage": {
if (!isActionEnabled("messages")) {
throw new Error("Discord message deletes are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
await deleteMessageDiscord(channelId, messageId);
return jsonResult({ ok: true });
}
case "threadCreate": {
if (!isActionEnabled("threads")) {
throw new Error("Discord threads are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const name = readStringParam(params, "name", { required: true });
const messageId = readStringParam(params, "messageId");
const autoArchiveMinutesRaw = params.autoArchiveMinutes;
const autoArchiveMinutes =
typeof autoArchiveMinutesRaw === "number" &&
Number.isFinite(autoArchiveMinutesRaw)
? autoArchiveMinutesRaw
: undefined;
const thread = await createThreadDiscord(channelId, {
name,
messageId,
autoArchiveMinutes,
});
return jsonResult({ ok: true, thread });
}
case "threadList": {
if (!isActionEnabled("threads")) {
throw new Error("Discord threads are disabled.");
}
const guildId = readStringParam(params, "guildId", {
required: true,
});
const channelId = readStringParam(params, "channelId");
const includeArchived =
typeof params.includeArchived === "boolean"
? params.includeArchived
: undefined;
const before = readStringParam(params, "before");
const limit =
typeof params.limit === "number" && Number.isFinite(params.limit)
? params.limit
: undefined;
const threads = await listThreadsDiscord({
guildId,
channelId,
includeArchived,
before,
limit,
});
return jsonResult({ ok: true, threads });
}
case "threadReply": {
if (!isActionEnabled("threads")) {
throw new Error("Discord threads are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const content = readStringParam(params, "content", {
required: true,
});
const mediaUrl = readStringParam(params, "mediaUrl");
const replyTo = readStringParam(params, "replyTo");
const result = await sendMessageDiscord(`channel:${channelId}`, content, {
mediaUrl,
replyTo,
});
return jsonResult({ ok: true, result });
}
case "pinMessage": {
if (!isActionEnabled("pins")) {
throw new Error("Discord pins are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
await pinMessageDiscord(channelId, messageId);
return jsonResult({ ok: true });
}
case "unpinMessage": {
if (!isActionEnabled("pins")) {
throw new Error("Discord pins are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const messageId = readStringParam(params, "messageId", {
required: true,
});
await unpinMessageDiscord(channelId, messageId);
return jsonResult({ ok: true });
}
case "listPins": {
if (!isActionEnabled("pins")) {
throw new Error("Discord pins are disabled.");
}
const channelId = readStringParam(params, "channelId", {
required: true,
});
const pins = await listPinsDiscord(channelId);
return jsonResult({ ok: true, pins });
}
case "searchMessages": {
if (!isActionEnabled("search")) {
throw new Error("Discord search is disabled.");
}
const guildId = readStringParam(params, "guildId", {
required: true,
});
const content = readStringParam(params, "content", {
required: true,
});
const channelId = readStringParam(params, "channelId");
const channelIds = readStringArrayParam(params, "channelIds");
const authorId = readStringParam(params, "authorId");
const authorIds = readStringArrayParam(params, "authorIds");
const limit =
typeof params.limit === "number" && Number.isFinite(params.limit)
? params.limit
: undefined;
const channelIdList = [
...(channelIds ?? []),
...(channelId ? [channelId] : []),
];
const authorIdList = [
...(authorIds ?? []),
...(authorId ? [authorId] : []),
];
const results = await searchMessagesDiscord({
guildId,
content,
channelIds: channelIdList.length ? channelIdList : undefined,
authorIds: authorIdList.length ? authorIdList : undefined,
limit,
});
return jsonResult({ ok: true, results });
}
default:
throw new Error(`Unknown action: ${action}`);
}
}