Discord: honor accountId across channel actions (refs #1489)

This commit is contained in:
Sergii Kozak
2026-01-23 00:50:50 -08:00
parent dc89bc4004
commit 716f901504
8 changed files with 322 additions and 146 deletions

View File

@@ -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({

View File

@@ -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;
}
}

View File

@@ -39,6 +39,9 @@ export async function handleDiscordGuildAction(
params: Record<string, unknown>,
isActionEnabled: ActionGate<DiscordActionConfig>,
): Promise<AgentToolResult<unknown>> {
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:

View File

@@ -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 });
}

View File

@@ -8,6 +8,9 @@ export async function handleDiscordModerationAction(
params: Record<string, unknown>,
isActionEnabled: ActionGate<DiscordActionConfig>,
): Promise<AgentToolResult<unknown>> {
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:

View File

@@ -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<Parameters<SendMessageDiscord>, ReturnType<SendMessageDiscord>>(
async () => ({ ok: true }) as Awaited<ReturnType<SendMessageDiscord>>,
@@ -10,6 +11,9 @@ const sendMessageDiscord = vi.fn<Parameters<SendMessageDiscord>, ReturnType<Send
const sendPollDiscord = vi.fn<Parameters<SendPollDiscord>, ReturnType<SendPollDiscord>>(
async () => ({ ok: true }) as Awaited<ReturnType<SendPollDiscord>>,
);
const reactMessageDiscord = vi.fn<Parameters<ReactMessageDiscord>, ReturnType<ReactMessageDiscord>>(
async () => ({ ok: true }) as Awaited<ReturnType<ReactMessageDiscord>>,
);
vi.mock("../../../discord/send.js", async () => {
const actual = await vi.importActual<typeof import("../../../discord/send.js")>(
@@ -19,6 +23,7 @@ vi.mock("../../../discord/send.js", async () => {
...actual,
sendMessageDiscord: (...args: Parameters<SendMessageDiscord>) => sendMessageDiscord(...args),
sendPollDiscord: (...args: Parameters<SendPollDiscord>) => sendPollDiscord(...args),
reactMessageDiscord: (...args: Parameters<ReactMessageDiscord>) => 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",
}),
);
});
});

View File

@@ -7,7 +7,7 @@ import {
import { handleDiscordAction } from "../../../../agents/tools/discord-actions.js";
import type { ChannelMessageActionContext } from "../../types.js";
type Ctx = Pick<ChannelMessageActionContext, "action" | "params" | "cfg">;
type Ctx = Pick<ChannelMessageActionContext, "action" | "params" | "cfg" | "accountId">;
export async function tryHandleDiscordMessageActionGuildAdmin(params: {
ctx: Ctx;
@@ -16,27 +16,38 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: {
}): Promise<AgentToolResult<unknown> | 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"),

View File

@@ -22,6 +22,7 @@ export async function handleDiscordMessageAction(
): Promise<AgentToolResult<unknown>> {
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"),