From 716f9015044cfeeb873daf3d4bdf4682c452c90a Mon Sep 17 00:00:00 2001 From: Sergii Kozak Date: Fri, 23 Jan 2026 00:50:50 -0800 Subject: [PATCH] Discord: honor accountId across channel actions (refs #1489) --- src/agents/tools/cron-tool.test.ts | 21 +++ src/agents/tools/cron-tool.ts | 2 +- src/agents/tools/discord-actions-guild.ts | 163 ++++++++++-------- src/agents/tools/discord-actions-messaging.ts | 112 +++++++----- .../tools/discord-actions-moderation.ts | 37 ++-- src/channels/plugins/actions/discord.test.ts | 30 ++++ .../discord/handle-action.guild-admin.ts | 72 ++++++-- .../plugins/actions/discord/handle-action.ts | 31 +++- 8 files changed, 322 insertions(+), 146 deletions(-) diff --git a/src/agents/tools/cron-tool.test.ts b/src/agents/tools/cron-tool.test.ts index 4b7cd6615..08bd9a834 100644 --- a/src/agents/tools/cron-tool.test.ts +++ b/src/agents/tools/cron-tool.test.ts @@ -5,6 +5,10 @@ vi.mock("../../gateway/call.js", () => ({ callGateway: (opts: unknown) => callGatewayMock(opts), })); +vi.mock("../agent-scope.js", () => ({ + resolveSessionAgentId: () => "agent-123", +})); + import { createCronTool } from "./cron-tool.js"; describe("cron tool", () => { @@ -85,6 +89,23 @@ describe("cron tool", () => { }); }); + it("does not default agentId when job.agentId is null", async () => { + const tool = createCronTool({ agentSessionKey: "main" }); + await tool.execute("call-null", { + action: "add", + job: { + name: "wake-up", + schedule: { atMs: 123 }, + agentId: null, + }, + }); + + const call = callGatewayMock.mock.calls[0]?.[0] as { + params?: { agentId?: unknown }; + }; + expect(call?.params?.agentId).toBeNull(); + }); + it("adds recent context for systemEvent reminders when contextMessages > 0", async () => { callGatewayMock .mockResolvedValueOnce({ diff --git a/src/agents/tools/cron-tool.ts b/src/agents/tools/cron-tool.ts index e640a8d94..e1bc15024 100644 --- a/src/agents/tools/cron-tool.ts +++ b/src/agents/tools/cron-tool.ts @@ -164,7 +164,7 @@ export function createCronTool(opts?: CronToolOptions): AnyAgentTool { const agentId = opts?.agentSessionKey ? resolveSessionAgentId({ sessionKey: opts.agentSessionKey, config: cfg }) : undefined; - if (agentId && !(job as { agentId?: unknown }).agentId) { + if (agentId && !("agentId" in (job as { agentId?: unknown }))) { (job as { agentId?: string }).agentId = agentId; } } diff --git a/src/agents/tools/discord-actions-guild.ts b/src/agents/tools/discord-actions-guild.ts index cf43f90af..ce21bacfd 100644 --- a/src/agents/tools/discord-actions-guild.ts +++ b/src/agents/tools/discord-actions-guild.ts @@ -39,6 +39,9 @@ export async function handleDiscordGuildAction( params: Record, isActionEnabled: ActionGate, ): Promise> { + const accountId = readStringParam(params, "accountId"); + const accountOpts = accountId ? { accountId } : {}; + switch (action) { case "memberInfo": { if (!isActionEnabled("memberInfo")) { @@ -50,7 +53,7 @@ export async function handleDiscordGuildAction( const userId = readStringParam(params, "userId", { required: true, }); - const member = await fetchMemberInfoDiscord(guildId, userId); + const member = await fetchMemberInfoDiscord(guildId, userId, accountOpts); return jsonResult({ ok: true, member }); } case "roleInfo": { @@ -60,7 +63,7 @@ export async function handleDiscordGuildAction( const guildId = readStringParam(params, "guildId", { required: true, }); - const roles = await fetchRoleInfoDiscord(guildId); + const roles = await fetchRoleInfoDiscord(guildId, accountOpts); return jsonResult({ ok: true, roles }); } case "emojiList": { @@ -70,7 +73,7 @@ export async function handleDiscordGuildAction( const guildId = readStringParam(params, "guildId", { required: true, }); - const emojis = await listGuildEmojisDiscord(guildId); + const emojis = await listGuildEmojisDiscord(guildId, accountOpts); return jsonResult({ ok: true, emojis }); } case "emojiUpload": { @@ -85,12 +88,15 @@ export async function handleDiscordGuildAction( required: true, }); const roleIds = readStringArrayParam(params, "roleIds"); - const emoji = await uploadEmojiDiscord({ - guildId, - name, - mediaUrl, - roleIds: roleIds?.length ? roleIds : undefined, - }); + const emoji = await uploadEmojiDiscord( + { + guildId, + name, + mediaUrl, + roleIds: roleIds?.length ? roleIds : undefined, + }, + accountOpts, + ); return jsonResult({ ok: true, emoji }); } case "stickerUpload": { @@ -108,13 +114,16 @@ export async function handleDiscordGuildAction( const mediaUrl = readStringParam(params, "mediaUrl", { required: true, }); - const sticker = await uploadStickerDiscord({ - guildId, - name, - description, - tags, - mediaUrl, - }); + const sticker = await uploadStickerDiscord( + { + guildId, + name, + description, + tags, + mediaUrl, + }, + accountOpts, + ); return jsonResult({ ok: true, sticker }); } case "roleAdd": { @@ -128,7 +137,7 @@ export async function handleDiscordGuildAction( required: true, }); const roleId = readStringParam(params, "roleId", { required: true }); - await addRoleDiscord({ guildId, userId, roleId }); + await addRoleDiscord({ guildId, userId, roleId }, accountOpts); return jsonResult({ ok: true }); } case "roleRemove": { @@ -142,7 +151,7 @@ export async function handleDiscordGuildAction( required: true, }); const roleId = readStringParam(params, "roleId", { required: true }); - await removeRoleDiscord({ guildId, userId, roleId }); + await removeRoleDiscord({ guildId, userId, roleId }, accountOpts); return jsonResult({ ok: true }); } case "channelInfo": { @@ -152,7 +161,7 @@ export async function handleDiscordGuildAction( const channelId = readStringParam(params, "channelId", { required: true, }); - const channel = await fetchChannelInfoDiscord(channelId); + const channel = await fetchChannelInfoDiscord(channelId, accountOpts); return jsonResult({ ok: true, channel }); } case "channelList": { @@ -162,7 +171,7 @@ export async function handleDiscordGuildAction( const guildId = readStringParam(params, "guildId", { required: true, }); - const channels = await listGuildChannelsDiscord(guildId); + const channels = await listGuildChannelsDiscord(guildId, accountOpts); return jsonResult({ ok: true, channels }); } case "voiceStatus": { @@ -175,7 +184,7 @@ export async function handleDiscordGuildAction( const userId = readStringParam(params, "userId", { required: true, }); - const voice = await fetchVoiceStatusDiscord(guildId, userId); + const voice = await fetchVoiceStatusDiscord(guildId, userId, accountOpts); return jsonResult({ ok: true, voice }); } case "eventList": { @@ -185,7 +194,7 @@ export async function handleDiscordGuildAction( const guildId = readStringParam(params, "guildId", { required: true, }); - const events = await listScheduledEventsDiscord(guildId); + const events = await listScheduledEventsDiscord(guildId, accountOpts); return jsonResult({ ok: true, events }); } case "eventCreate": { @@ -215,7 +224,7 @@ export async function handleDiscordGuildAction( entity_metadata: entityType === 3 && location ? { location } : undefined, privacy_level: 2, }; - const event = await createScheduledEventDiscord(guildId, payload); + const event = await createScheduledEventDiscord(guildId, payload, accountOpts); return jsonResult({ ok: true, event }); } case "channelCreate": { @@ -229,15 +238,18 @@ export async function handleDiscordGuildAction( const topic = readStringParam(params, "topic"); const position = readNumberParam(params, "position", { integer: true }); const nsfw = params.nsfw as boolean | undefined; - const channel = await createChannelDiscord({ - guildId, - name, - type: type ?? undefined, - parentId: parentId ?? undefined, - topic: topic ?? undefined, - position: position ?? undefined, - nsfw, - }); + const channel = await createChannelDiscord( + { + guildId, + name, + type: type ?? undefined, + parentId: parentId ?? undefined, + topic: topic ?? undefined, + position: position ?? undefined, + nsfw, + }, + accountOpts, + ); return jsonResult({ ok: true, channel }); } case "channelEdit": { @@ -255,15 +267,18 @@ export async function handleDiscordGuildAction( const rateLimitPerUser = readNumberParam(params, "rateLimitPerUser", { integer: true, }); - const channel = await editChannelDiscord({ - channelId, - name: name ?? undefined, - topic: topic ?? undefined, - position: position ?? undefined, - parentId, - nsfw, - rateLimitPerUser: rateLimitPerUser ?? undefined, - }); + const channel = await editChannelDiscord( + { + channelId, + name: name ?? undefined, + topic: topic ?? undefined, + position: position ?? undefined, + parentId, + nsfw, + rateLimitPerUser: rateLimitPerUser ?? undefined, + }, + accountOpts, + ); return jsonResult({ ok: true, channel }); } case "channelDelete": { @@ -273,7 +288,7 @@ export async function handleDiscordGuildAction( const channelId = readStringParam(params, "channelId", { required: true, }); - const result = await deleteChannelDiscord(channelId); + const result = await deleteChannelDiscord(channelId, accountOpts); return jsonResult(result); } case "channelMove": { @@ -286,12 +301,15 @@ export async function handleDiscordGuildAction( }); const parentId = readParentIdParam(params); const position = readNumberParam(params, "position", { integer: true }); - await moveChannelDiscord({ - guildId, - channelId, - parentId, - position: position ?? undefined, - }); + await moveChannelDiscord( + { + guildId, + channelId, + parentId, + position: position ?? undefined, + }, + accountOpts, + ); return jsonResult({ ok: true }); } case "categoryCreate": { @@ -301,12 +319,15 @@ export async function handleDiscordGuildAction( const guildId = readStringParam(params, "guildId", { required: true }); const name = readStringParam(params, "name", { required: true }); const position = readNumberParam(params, "position", { integer: true }); - const channel = await createChannelDiscord({ - guildId, - name, - type: 4, - position: position ?? undefined, - }); + const channel = await createChannelDiscord( + { + guildId, + name, + type: 4, + position: position ?? undefined, + }, + accountOpts, + ); return jsonResult({ ok: true, category: channel }); } case "categoryEdit": { @@ -318,11 +339,14 @@ export async function handleDiscordGuildAction( }); const name = readStringParam(params, "name"); const position = readNumberParam(params, "position", { integer: true }); - const channel = await editChannelDiscord({ - channelId: categoryId, - name: name ?? undefined, - position: position ?? undefined, - }); + const channel = await editChannelDiscord( + { + channelId: categoryId, + name: name ?? undefined, + position: position ?? undefined, + }, + accountOpts, + ); return jsonResult({ ok: true, category: channel }); } case "categoryDelete": { @@ -332,7 +356,7 @@ export async function handleDiscordGuildAction( const categoryId = readStringParam(params, "categoryId", { required: true, }); - const result = await deleteChannelDiscord(categoryId); + const result = await deleteChannelDiscord(categoryId, accountOpts); return jsonResult(result); } case "channelPermissionSet": { @@ -349,13 +373,16 @@ export async function handleDiscordGuildAction( const targetType = targetTypeRaw === "member" ? 1 : 0; const allow = readStringParam(params, "allow"); const deny = readStringParam(params, "deny"); - await setChannelPermissionDiscord({ - channelId, - targetId, - targetType, - allow: allow ?? undefined, - deny: deny ?? undefined, - }); + await setChannelPermissionDiscord( + { + channelId, + targetId, + targetType, + allow: allow ?? undefined, + deny: deny ?? undefined, + }, + accountOpts, + ); return jsonResult({ ok: true }); } case "channelPermissionRemove": { @@ -366,7 +393,7 @@ export async function handleDiscordGuildAction( required: true, }); const targetId = readStringParam(params, "targetId", { required: true }); - await removeChannelPermissionDiscord(channelId, targetId); + await removeChannelPermissionDiscord(channelId, targetId, accountOpts); return jsonResult({ ok: true }); } default: diff --git a/src/agents/tools/discord-actions-messaging.ts b/src/agents/tools/discord-actions-messaging.ts index ae49d25bf..eb4c0547f 100644 --- a/src/agents/tools/discord-actions-messaging.ts +++ b/src/agents/tools/discord-actions-messaging.ts @@ -65,6 +65,8 @@ export async function handleDiscordMessagingAction( (message as { timestamp?: unknown }).timestamp, ); }; + const accountId = readStringParam(params, "accountId"); + const accountOpts = accountId ? { accountId } : {}; switch (action) { case "react": { if (!isActionEnabled("reactions")) { @@ -78,14 +80,14 @@ export async function handleDiscordMessagingAction( removeErrorMessage: "Emoji is required to remove a Discord reaction.", }); if (remove) { - await removeReactionDiscord(channelId, messageId, emoji); + await removeReactionDiscord(channelId, messageId, emoji, accountOpts); return jsonResult({ ok: true, removed: emoji }); } if (isEmpty) { - const removed = await removeOwnReactionsDiscord(channelId, messageId); + const removed = await removeOwnReactionsDiscord(channelId, messageId, accountOpts); return jsonResult({ ok: true, removed: removed.removed }); } - await reactMessageDiscord(channelId, messageId, emoji); + await reactMessageDiscord(channelId, messageId, emoji, accountOpts); return jsonResult({ ok: true, added: emoji }); } case "reactions": { @@ -100,6 +102,7 @@ export async function handleDiscordMessagingAction( const limit = typeof limitRaw === "number" && Number.isFinite(limitRaw) ? limitRaw : undefined; const reactions = await fetchReactionsDiscord(channelId, messageId, { + ...accountOpts, limit, }); return jsonResult({ ok: true, reactions }); @@ -114,8 +117,10 @@ export async function handleDiscordMessagingAction( required: true, label: "stickerIds", }); - const accountId = readStringParam(params, "accountId"); - await sendStickerDiscord(to, stickerIds, { content, accountId: accountId ?? undefined }); + await sendStickerDiscord(to, stickerIds, { + content, + accountId: accountId ?? undefined, + }); return jsonResult({ ok: true }); } case "poll": { @@ -138,7 +143,6 @@ export async function handleDiscordMessagingAction( const durationHours = typeof durationRaw === "number" && Number.isFinite(durationRaw) ? durationRaw : undefined; const maxSelections = allowMultiselect ? Math.max(2, answers.length) : 1; - const accountId = readStringParam(params, "accountId"); await sendPollDiscord( to, { question, options: answers, maxSelections, durationHours }, @@ -151,7 +155,7 @@ export async function handleDiscordMessagingAction( throw new Error("Discord permissions are disabled."); } const channelId = resolveChannelId(); - const permissions = await fetchChannelPermissionsDiscord(channelId); + const permissions = await fetchChannelPermissionsDiscord(channelId, accountOpts); return jsonResult({ ok: true, permissions }); } case "fetchMessage": { @@ -173,7 +177,7 @@ export async function handleDiscordMessagingAction( "Discord message fetch requires guildId, channelId, and messageId (or a valid messageLink).", ); } - const message = await fetchMessageDiscord(channelId, messageId); + const message = await fetchMessageDiscord(channelId, messageId, accountOpts); return jsonResult({ ok: true, message: normalizeMessage(message), @@ -187,15 +191,19 @@ export async function handleDiscordMessagingAction( throw new Error("Discord message reads are disabled."); } const channelId = resolveChannelId(); - 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"), - }); + 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"), + }, + accountOpts, + ); return jsonResult({ ok: true, messages: messages.map((message) => normalizeMessage(message)), @@ -213,8 +221,6 @@ export async function handleDiscordMessagingAction( const replyTo = readStringParam(params, "replyTo"); const embeds = Array.isArray(params.embeds) && params.embeds.length > 0 ? params.embeds : undefined; - const accountId = readStringParam(params, "accountId"); - const result = await sendMessageDiscord(to, content, { accountId: accountId ?? undefined, mediaUrl, @@ -234,9 +240,14 @@ export async function handleDiscordMessagingAction( const content = readStringParam(params, "content", { required: true, }); - const message = await editMessageDiscord(channelId, messageId, { - content, - }); + const message = await editMessageDiscord( + channelId, + messageId, + { + content, + }, + accountOpts, + ); return jsonResult({ ok: true, message }); } case "deleteMessage": { @@ -247,7 +258,7 @@ export async function handleDiscordMessagingAction( const messageId = readStringParam(params, "messageId", { required: true, }); - await deleteMessageDiscord(channelId, messageId); + await deleteMessageDiscord(channelId, messageId, accountOpts); return jsonResult({ ok: true }); } case "threadCreate": { @@ -262,11 +273,15 @@ export async function handleDiscordMessagingAction( typeof autoArchiveMinutesRaw === "number" && Number.isFinite(autoArchiveMinutesRaw) ? autoArchiveMinutesRaw : undefined; - const thread = await createThreadDiscord(channelId, { - name, - messageId, - autoArchiveMinutes, - }); + const thread = await createThreadDiscord( + channelId, + { + name, + messageId, + autoArchiveMinutes, + }, + accountOpts, + ); return jsonResult({ ok: true, thread }); } case "threadList": { @@ -284,13 +299,16 @@ export async function handleDiscordMessagingAction( typeof params.limit === "number" && Number.isFinite(params.limit) ? params.limit : undefined; - const threads = await listThreadsDiscord({ - guildId, - channelId, - includeArchived, - before, - limit, - }); + const threads = await listThreadsDiscord( + { + guildId, + channelId, + includeArchived, + before, + limit, + }, + accountOpts, + ); return jsonResult({ ok: true, threads }); } case "threadReply": { @@ -303,7 +321,6 @@ export async function handleDiscordMessagingAction( }); const mediaUrl = readStringParam(params, "mediaUrl"); const replyTo = readStringParam(params, "replyTo"); - const accountId = readStringParam(params, "accountId"); const result = await sendMessageDiscord(`channel:${channelId}`, content, { accountId: accountId ?? undefined, mediaUrl, @@ -319,7 +336,7 @@ export async function handleDiscordMessagingAction( const messageId = readStringParam(params, "messageId", { required: true, }); - await pinMessageDiscord(channelId, messageId); + await pinMessageDiscord(channelId, messageId, accountOpts); return jsonResult({ ok: true }); } case "unpinMessage": { @@ -330,7 +347,7 @@ export async function handleDiscordMessagingAction( const messageId = readStringParam(params, "messageId", { required: true, }); - await unpinMessageDiscord(channelId, messageId); + await unpinMessageDiscord(channelId, messageId, accountOpts); return jsonResult({ ok: true }); } case "listPins": { @@ -338,7 +355,7 @@ export async function handleDiscordMessagingAction( throw new Error("Discord pins are disabled."); } const channelId = resolveChannelId(); - const pins = await listPinsDiscord(channelId); + const pins = await listPinsDiscord(channelId, accountOpts); return jsonResult({ ok: true, pins: pins.map((pin) => normalizeMessage(pin)) }); } case "searchMessages": { @@ -361,13 +378,16 @@ export async function handleDiscordMessagingAction( : 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, - }); + const results = await searchMessagesDiscord( + { + guildId, + content, + channelIds: channelIdList.length ? channelIdList : undefined, + authorIds: authorIdList.length ? authorIdList : undefined, + limit, + }, + accountOpts, + ); if (!results || typeof results !== "object") { return jsonResult({ ok: true, results }); } diff --git a/src/agents/tools/discord-actions-moderation.ts b/src/agents/tools/discord-actions-moderation.ts index 260ce85ea..5889d4880 100644 --- a/src/agents/tools/discord-actions-moderation.ts +++ b/src/agents/tools/discord-actions-moderation.ts @@ -8,6 +8,9 @@ export async function handleDiscordModerationAction( params: Record, isActionEnabled: ActionGate, ): Promise> { + const accountId = readStringParam(params, "accountId"); + const accountOpts = accountId ? { accountId } : {}; + switch (action) { case "timeout": { if (!isActionEnabled("moderation", false)) { @@ -25,13 +28,16 @@ export async function handleDiscordModerationAction( : undefined; const until = readStringParam(params, "until"); const reason = readStringParam(params, "reason"); - const member = await timeoutMemberDiscord({ - guildId, - userId, - durationMinutes, - until, - reason, - }); + const member = await timeoutMemberDiscord( + { + guildId, + userId, + durationMinutes, + until, + reason, + }, + accountOpts, + ); return jsonResult({ ok: true, member }); } case "kick": { @@ -45,7 +51,7 @@ export async function handleDiscordModerationAction( required: true, }); const reason = readStringParam(params, "reason"); - await kickMemberDiscord({ guildId, userId, reason }); + await kickMemberDiscord({ guildId, userId, reason }, accountOpts); return jsonResult({ ok: true }); } case "ban": { @@ -63,12 +69,15 @@ export async function handleDiscordModerationAction( typeof params.deleteMessageDays === "number" && Number.isFinite(params.deleteMessageDays) ? params.deleteMessageDays : undefined; - await banMemberDiscord({ - guildId, - userId, - reason, - deleteMessageDays, - }); + await banMemberDiscord( + { + guildId, + userId, + reason, + deleteMessageDays, + }, + accountOpts, + ); return jsonResult({ ok: true }); } default: diff --git a/src/channels/plugins/actions/discord.test.ts b/src/channels/plugins/actions/discord.test.ts index 8deda7dc6..d38f0ba88 100644 --- a/src/channels/plugins/actions/discord.test.ts +++ b/src/channels/plugins/actions/discord.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it, vi } from "vitest"; import type { ClawdbotConfig } from "../../../config/config.js"; type SendMessageDiscord = typeof import("../../../discord/send.js").sendMessageDiscord; type SendPollDiscord = typeof import("../../../discord/send.js").sendPollDiscord; +type ReactMessageDiscord = typeof import("../../../discord/send.js").reactMessageDiscord; const sendMessageDiscord = vi.fn, ReturnType>( async () => ({ ok: true }) as Awaited>, @@ -10,6 +11,9 @@ const sendMessageDiscord = vi.fn, ReturnType, ReturnType>( async () => ({ ok: true }) as Awaited>, ); +const reactMessageDiscord = vi.fn, ReturnType>( + async () => ({ ok: true }) as Awaited>, +); vi.mock("../../../discord/send.js", async () => { const actual = await vi.importActual( @@ -19,6 +23,7 @@ vi.mock("../../../discord/send.js", async () => { ...actual, sendMessageDiscord: (...args: Parameters) => sendMessageDiscord(...args), sendPollDiscord: (...args: Parameters) => sendPollDiscord(...args), + reactMessageDiscord: (...args: Parameters) => reactMessageDiscord(...args), }; }); @@ -104,4 +109,29 @@ describe("handleDiscordMessageAction", () => { }), ); }); + + it("forwards accountId for reaction actions", async () => { + reactMessageDiscord.mockClear(); + const handleDiscordMessageAction = await loadHandleDiscordMessageAction(); + + await handleDiscordMessageAction({ + action: "react", + params: { + channelId: "123", + messageId: "m1", + emoji: "👍", + }, + cfg: {} as ClawdbotConfig, + accountId: "ops", + }); + + expect(reactMessageDiscord).toHaveBeenCalledWith( + "123", + "m1", + "👍", + expect.objectContaining({ + accountId: "ops", + }), + ); + }); }); diff --git a/src/channels/plugins/actions/discord/handle-action.guild-admin.ts b/src/channels/plugins/actions/discord/handle-action.guild-admin.ts index c2470e1dd..90091d881 100644 --- a/src/channels/plugins/actions/discord/handle-action.guild-admin.ts +++ b/src/channels/plugins/actions/discord/handle-action.guild-admin.ts @@ -7,7 +7,7 @@ import { import { handleDiscordAction } from "../../../../agents/tools/discord-actions.js"; import type { ChannelMessageActionContext } from "../../types.js"; -type Ctx = Pick; +type Ctx = Pick; export async function tryHandleDiscordMessageActionGuildAdmin(params: { ctx: Ctx; @@ -16,27 +16,38 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { }): 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", guildId, userId }, cfg); + 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", guildId }, cfg); + 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", guildId }, cfg); + return await handleDiscordAction( + { action: "emojiList", accountId: accountIdParam, guildId }, + cfg, + ); } if (action === "emoji-upload") { @@ -50,7 +61,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { }); const roleIds = readStringArrayParam(actionParams, "roleIds"); return await handleDiscordAction( - { action: "emojiUpload", guildId, name, mediaUrl, roleIds }, + { action: "emojiUpload", accountId: accountIdParam, guildId, name, mediaUrl, roleIds }, cfg, ); } @@ -73,7 +84,15 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { trim: false, }); return await handleDiscordAction( - { action: "stickerUpload", guildId, name, description, tags, mediaUrl }, + { + action: "stickerUpload", + accountId: accountIdParam, + guildId, + name, + description, + tags, + mediaUrl, + }, cfg, ); } @@ -87,6 +106,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: action === "role-add" ? "roleAdd" : "roleRemove", + accountId: accountIdParam, guildId, userId, roleId, @@ -99,14 +119,20 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { const channelId = readStringParam(actionParams, "channelId", { required: true, }); - return await handleDiscordAction({ action: "channelInfo", channelId }, cfg); + 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", guildId }, cfg); + return await handleDiscordAction( + { action: "channelList", accountId: accountIdParam, guildId }, + cfg, + ); } if (action === "channel-create") { @@ -124,6 +150,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "channelCreate", + accountId: accountIdParam, guildId, name, type: type ?? undefined, @@ -153,6 +180,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "channelEdit", + accountId: accountIdParam, channelId, name: name ?? undefined, topic: topic ?? undefined, @@ -169,7 +197,10 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { const channelId = readStringParam(actionParams, "channelId", { required: true, }); - return await handleDiscordAction({ action: "channelDelete", channelId }, cfg); + return await handleDiscordAction( + { action: "channelDelete", accountId: accountIdParam, channelId }, + cfg, + ); } if (action === "channel-move") { @@ -186,6 +217,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "channelMove", + accountId: accountIdParam, guildId, channelId, parentId: parentId === undefined ? undefined : parentId, @@ -206,6 +238,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "categoryCreate", + accountId: accountIdParam, guildId, name, position: position ?? undefined, @@ -225,6 +258,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "categoryEdit", + accountId: accountIdParam, categoryId, name: name ?? undefined, position: position ?? undefined, @@ -237,7 +271,10 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { const categoryId = readStringParam(actionParams, "categoryId", { required: true, }); - return await handleDiscordAction({ action: "categoryDelete", categoryId }, cfg); + return await handleDiscordAction( + { action: "categoryDelete", accountId: accountIdParam, categoryId }, + cfg, + ); } if (action === "voice-status") { @@ -245,14 +282,20 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { required: true, }); const userId = readStringParam(actionParams, "userId", { required: true }); - return await handleDiscordAction({ action: "voiceStatus", guildId, userId }, cfg); + 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", guildId }, cfg); + return await handleDiscordAction( + { action: "eventList", accountId: accountIdParam, guildId }, + cfg, + ); } if (action === "event-create") { @@ -271,6 +314,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "eventCreate", + accountId: accountIdParam, guildId, name, startTime, @@ -301,6 +345,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: discordAction, + accountId: accountIdParam, guildId, userId, durationMinutes, @@ -325,6 +370,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "threadList", + accountId: accountIdParam, guildId, channelId, includeArchived, @@ -344,6 +390,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "threadReply", + accountId: accountIdParam, channelId: resolveChannelId(), content, mediaUrl: mediaUrl ?? undefined, @@ -361,6 +408,7 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: { return await handleDiscordAction( { action: "searchMessages", + accountId: accountIdParam, guildId, content: query, channelId: readStringParam(actionParams, "channelId"), diff --git a/src/channels/plugins/actions/discord/handle-action.ts b/src/channels/plugins/actions/discord/handle-action.ts index 031ca9f5b..6c14ad209 100644 --- a/src/channels/plugins/actions/discord/handle-action.ts +++ b/src/channels/plugins/actions/discord/handle-action.ts @@ -22,6 +22,7 @@ export async function handleDiscordMessageAction( ): Promise> { const { action, params, cfg } = ctx; const accountId = ctx.accountId ?? readStringParam(params, "accountId"); + const accountIdParam = accountId ?? undefined; const resolveChannelId = () => resolveDiscordChannelId( @@ -40,7 +41,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "sendMessage", - accountId: accountId ?? undefined, + accountId: accountIdParam, to, content, mediaUrl: mediaUrl ?? undefined, @@ -64,7 +65,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "poll", - accountId: accountId ?? undefined, + accountId: accountIdParam, to, question, answers, @@ -83,6 +84,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "react", + accountId: accountIdParam, channelId: resolveChannelId(), messageId, emoji, @@ -96,7 +98,13 @@ export async function handleDiscordMessageAction( const messageId = readStringParam(params, "messageId", { required: true }); const limit = readNumberParam(params, "limit", { integer: true }); return await handleDiscordAction( - { action: "reactions", channelId: resolveChannelId(), messageId, limit }, + { + action: "reactions", + accountId: accountIdParam, + channelId: resolveChannelId(), + messageId, + limit, + }, cfg, ); } @@ -106,6 +114,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "readMessages", + accountId: accountIdParam, channelId: resolveChannelId(), limit, before: readStringParam(params, "before"), @@ -122,6 +131,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "editMessage", + accountId: accountIdParam, channelId: resolveChannelId(), messageId, content, @@ -133,7 +143,12 @@ export async function handleDiscordMessageAction( if (action === "delete") { const messageId = readStringParam(params, "messageId", { required: true }); return await handleDiscordAction( - { action: "deleteMessage", channelId: resolveChannelId(), messageId }, + { + action: "deleteMessage", + accountId: accountIdParam, + channelId: resolveChannelId(), + messageId, + }, cfg, ); } @@ -144,6 +159,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins", + accountId: accountIdParam, channelId: resolveChannelId(), messageId, }, @@ -152,7 +168,10 @@ export async function handleDiscordMessageAction( } if (action === "permissions") { - return await handleDiscordAction({ action: "permissions", channelId: resolveChannelId() }, cfg); + return await handleDiscordAction( + { action: "permissions", accountId: accountIdParam, channelId: resolveChannelId() }, + cfg, + ); } if (action === "thread-create") { @@ -164,6 +183,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "threadCreate", + accountId: accountIdParam, channelId: resolveChannelId(), name, messageId, @@ -182,6 +202,7 @@ export async function handleDiscordMessageAction( return await handleDiscordAction( { action: "sticker", + accountId: accountIdParam, to: readStringParam(params, "to", { required: true }), stickerIds, content: readStringParam(params, "message"),