import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import { readNumberParam, readStringArrayParam, readStringParam, } from "../../../../agents/tools/common.js"; import { handleDiscordAction } from "../../../../agents/tools/discord-actions.js"; import type { ChannelMessageActionContext } from "../../types.js"; type Ctx = Pick; export async function tryHandleDiscordMessageActionGuildAdmin(params: { ctx: Ctx; resolveChannelId: () => string; readParentIdParam: (params: Record) => string | null | undefined; }): Promise | undefined> { const { ctx, resolveChannelId, readParentIdParam } = params; const { action, params: actionParams, cfg } = ctx; const accountId = ctx.accountId ?? readStringParam(actionParams, "accountId"); const accountIdParam = accountId ?? undefined; if (action === "member-info") { const userId = readStringParam(actionParams, "userId", { required: true }); const guildId = readStringParam(actionParams, "guildId", { required: true, }); return await handleDiscordAction( { action: "memberInfo", accountId: accountIdParam, guildId, userId }, cfg, ); } if (action === "role-info") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); return await handleDiscordAction( { action: "roleInfo", accountId: accountIdParam, guildId }, cfg, ); } if (action === "emoji-list") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); return await handleDiscordAction( { action: "emojiList", accountId: accountIdParam, guildId }, cfg, ); } if (action === "emoji-upload") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const name = readStringParam(actionParams, "emojiName", { required: true }); const mediaUrl = readStringParam(actionParams, "media", { required: true, trim: false, }); const roleIds = readStringArrayParam(actionParams, "roleIds"); return await handleDiscordAction( { action: "emojiUpload", accountId: accountIdParam, guildId, name, mediaUrl, roleIds }, cfg, ); } if (action === "sticker-upload") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const name = readStringParam(actionParams, "stickerName", { required: true, }); const description = readStringParam(actionParams, "stickerDesc", { required: true, }); const tags = readStringParam(actionParams, "stickerTags", { required: true, }); const mediaUrl = readStringParam(actionParams, "media", { required: true, trim: false, }); return await handleDiscordAction( { action: "stickerUpload", accountId: accountIdParam, guildId, name, description, tags, mediaUrl, }, cfg, ); } if (action === "role-add" || action === "role-remove") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const userId = readStringParam(actionParams, "userId", { required: true }); const roleId = readStringParam(actionParams, "roleId", { required: true }); return await handleDiscordAction( { action: action === "role-add" ? "roleAdd" : "roleRemove", accountId: accountIdParam, guildId, userId, roleId, }, cfg, ); } if (action === "channel-info") { const channelId = readStringParam(actionParams, "channelId", { required: true, }); return await handleDiscordAction( { action: "channelInfo", accountId: accountIdParam, channelId }, cfg, ); } if (action === "channel-list") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); return await handleDiscordAction( { action: "channelList", accountId: accountIdParam, guildId }, cfg, ); } if (action === "channel-create") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const name = readStringParam(actionParams, "name", { required: true }); const type = readNumberParam(actionParams, "type", { integer: true }); const parentId = readParentIdParam(actionParams); const topic = readStringParam(actionParams, "topic"); const position = readNumberParam(actionParams, "position", { integer: true, }); const nsfw = typeof actionParams.nsfw === "boolean" ? actionParams.nsfw : undefined; return await handleDiscordAction( { action: "channelCreate", accountId: accountIdParam, guildId, name, type: type ?? undefined, parentId: parentId ?? undefined, topic: topic ?? undefined, position: position ?? undefined, nsfw, }, cfg, ); } if (action === "channel-edit") { const channelId = readStringParam(actionParams, "channelId", { required: true, }); const name = readStringParam(actionParams, "name"); const topic = readStringParam(actionParams, "topic"); const position = readNumberParam(actionParams, "position", { integer: true, }); const parentId = readParentIdParam(actionParams); const nsfw = typeof actionParams.nsfw === "boolean" ? actionParams.nsfw : undefined; const rateLimitPerUser = readNumberParam(actionParams, "rateLimitPerUser", { integer: true, }); return await handleDiscordAction( { action: "channelEdit", accountId: accountIdParam, channelId, name: name ?? undefined, topic: topic ?? undefined, position: position ?? undefined, parentId: parentId === undefined ? undefined : parentId, nsfw, rateLimitPerUser: rateLimitPerUser ?? undefined, }, cfg, ); } if (action === "channel-delete") { const channelId = readStringParam(actionParams, "channelId", { required: true, }); return await handleDiscordAction( { action: "channelDelete", accountId: accountIdParam, channelId }, cfg, ); } if (action === "channel-move") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const channelId = readStringParam(actionParams, "channelId", { required: true, }); const parentId = readParentIdParam(actionParams); const position = readNumberParam(actionParams, "position", { integer: true, }); return await handleDiscordAction( { action: "channelMove", accountId: accountIdParam, guildId, channelId, parentId: parentId === undefined ? undefined : parentId, position: position ?? undefined, }, cfg, ); } if (action === "category-create") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const name = readStringParam(actionParams, "name", { required: true }); const position = readNumberParam(actionParams, "position", { integer: true, }); return await handleDiscordAction( { action: "categoryCreate", accountId: accountIdParam, guildId, name, position: position ?? undefined, }, cfg, ); } if (action === "category-edit") { const categoryId = readStringParam(actionParams, "categoryId", { required: true, }); const name = readStringParam(actionParams, "name"); const position = readNumberParam(actionParams, "position", { integer: true, }); return await handleDiscordAction( { action: "categoryEdit", accountId: accountIdParam, categoryId, name: name ?? undefined, position: position ?? undefined, }, cfg, ); } if (action === "category-delete") { const categoryId = readStringParam(actionParams, "categoryId", { required: true, }); return await handleDiscordAction( { action: "categoryDelete", accountId: accountIdParam, categoryId }, cfg, ); } if (action === "voice-status") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const userId = readStringParam(actionParams, "userId", { required: true }); return await handleDiscordAction( { action: "voiceStatus", accountId: accountIdParam, guildId, userId }, cfg, ); } if (action === "event-list") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); return await handleDiscordAction( { action: "eventList", accountId: accountIdParam, guildId }, cfg, ); } if (action === "event-create") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const name = readStringParam(actionParams, "eventName", { required: true }); const startTime = readStringParam(actionParams, "startTime", { required: true, }); const endTime = readStringParam(actionParams, "endTime"); const description = readStringParam(actionParams, "desc"); const channelId = readStringParam(actionParams, "channelId"); const location = readStringParam(actionParams, "location"); const entityType = readStringParam(actionParams, "eventType"); return await handleDiscordAction( { action: "eventCreate", accountId: accountIdParam, guildId, name, startTime, endTime, description, channelId, location, entityType, }, cfg, ); } if (action === "timeout" || action === "kick" || action === "ban") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const userId = readStringParam(actionParams, "userId", { required: true }); const durationMinutes = readNumberParam(actionParams, "durationMin", { integer: true, }); const until = readStringParam(actionParams, "until"); const reason = readStringParam(actionParams, "reason"); const deleteMessageDays = readNumberParam(actionParams, "deleteDays", { integer: true, }); const discordAction = action as "timeout" | "kick" | "ban"; return await handleDiscordAction( { action: discordAction, accountId: accountIdParam, guildId, userId, durationMinutes, until, reason, deleteMessageDays, }, cfg, ); } // Some actions are conceptually "admin", but still act on a resolved channel. if (action === "thread-list") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const channelId = readStringParam(actionParams, "channelId"); const includeArchived = typeof actionParams.includeArchived === "boolean" ? actionParams.includeArchived : undefined; const before = readStringParam(actionParams, "before"); const limit = readNumberParam(actionParams, "limit", { integer: true }); return await handleDiscordAction( { action: "threadList", accountId: accountIdParam, guildId, channelId, includeArchived, before, limit, }, cfg, ); } if (action === "thread-reply") { const content = readStringParam(actionParams, "message", { required: true, }); const mediaUrl = readStringParam(actionParams, "media", { trim: false }); const replyTo = readStringParam(actionParams, "replyTo"); return await handleDiscordAction( { action: "threadReply", accountId: accountIdParam, channelId: resolveChannelId(), content, mediaUrl: mediaUrl ?? undefined, replyTo: replyTo ?? undefined, }, cfg, ); } if (action === "search") { const guildId = readStringParam(actionParams, "guildId", { required: true, }); const query = readStringParam(actionParams, "query", { required: true }); return await handleDiscordAction( { action: "searchMessages", accountId: accountIdParam, guildId, content: query, channelId: readStringParam(actionParams, "channelId"), channelIds: readStringArrayParam(actionParams, "channelIds"), authorId: readStringParam(actionParams, "authorId"), authorIds: readStringArrayParam(actionParams, "authorIds"), limit: readNumberParam(actionParams, "limit", { integer: true }), }, cfg, ); } return undefined; }