From 9e6b45faab44200382bc34c4f14bea5ca24a289f Mon Sep 17 00:00:00 2001
From: Paul Pamment
Date: Mon, 26 Jan 2026 17:00:34 +0000
Subject: [PATCH] fix(discord): honor threadId for thread-reply
---
src/channels/plugins/actions/discord.test.ts | 26 +++++++++++++++++++
.../discord/handle-action.guild-admin.ts | 8 +++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/src/channels/plugins/actions/discord.test.ts b/src/channels/plugins/actions/discord.test.ts
index 67047410e..9cc184e6c 100644
--- a/src/channels/plugins/actions/discord.test.ts
+++ b/src/channels/plugins/actions/discord.test.ts
@@ -127,4 +127,30 @@ describe("handleDiscordMessageAction", () => {
}),
);
});
+
+ it("accepts threadId for thread replies (tool compatibility)", async () => {
+ sendMessageDiscord.mockClear();
+ const handleDiscordMessageAction = await loadHandleDiscordMessageAction();
+
+ await handleDiscordMessageAction({
+ action: "thread-reply",
+ params: {
+ // The `message` tool uses `threadId`.
+ threadId: "999",
+ // Include a conflicting channelId to ensure threadId takes precedence.
+ channelId: "123",
+ message: "hi",
+ },
+ cfg: {} as ClawdbotConfig,
+ accountId: "ops",
+ });
+
+ expect(sendMessageDiscord).toHaveBeenCalledWith(
+ "channel:999",
+ "hi",
+ 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 d65d044e2..5a3b13f61 100644
--- a/src/channels/plugins/actions/discord/handle-action.guild-admin.ts
+++ b/src/channels/plugins/actions/discord/handle-action.guild-admin.ts
@@ -393,11 +393,17 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: {
});
const mediaUrl = readStringParam(actionParams, "media", { trim: false });
const replyTo = readStringParam(actionParams, "replyTo");
+
+ // `message.thread-reply` (tool) uses `threadId`, while the CLI historically used `to`/`channelId`.
+ // Prefer `threadId` when present to avoid accidentally replying in the parent channel.
+ const threadId = readStringParam(actionParams, "threadId");
+ const channelId = threadId ?? resolveChannelId();
+
return await handleDiscordAction(
{
action: "threadReply",
accountId: accountId ?? undefined,
- channelId: resolveChannelId(),
+ channelId,
content,
mediaUrl: mediaUrl ?? undefined,
replyTo: replyTo ?? undefined,