From 909c14d4439fb5939337d0f1fc028632ef5eb198 Mon Sep 17 00:00:00 2001 From: Austin Mudd Date: Fri, 9 Jan 2026 09:17:47 -0800 Subject: [PATCH] fix: resolve merge conflicts and fix threading tests - Update MessageToolOptions type to include Slack threading options - Remove duplicate threadTs property in slack/actions.ts - Fix replyThreadTs parameter name in monitor.ts - Update test to correctly verify 'first' mode threading behavior: - 'off' mode: no threading unless already in a thread - 'first' mode: first reply starts a thread - Add new test case for 'first' mode threading --- src/agents/tools/message-tool.ts | 8 +++++ src/slack/actions.ts | 1 - src/slack/monitor.tool-result.test.ts | 49 +++++++++++++++++++++++++-- src/slack/monitor.ts | 2 +- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/agents/tools/message-tool.ts b/src/agents/tools/message-tool.ts index d0d8d5d8f..50c1f51d5 100644 --- a/src/agents/tools/message-tool.ts +++ b/src/agents/tools/message-tool.ts @@ -134,6 +134,14 @@ const MessageToolSchema = Type.Object({ type MessageToolOptions = { agentAccountId?: string; config?: ClawdbotConfig; + /** Current channel ID for auto-threading (Slack). */ + currentChannelId?: string; + /** Current thread timestamp for auto-threading (Slack). */ + currentThreadTs?: string; + /** Reply-to mode for Slack auto-threading. */ + replyToMode?: "off" | "first" | "all"; + /** Mutable ref to track if a reply was sent (for "first" mode). */ + hasRepliedRef?: { value: boolean }; }; function hasTelegramInlineButtons(cfg: ClawdbotConfig): boolean { diff --git a/src/slack/actions.ts b/src/slack/actions.ts index 9c2b2cc9e..c108ebe72 100644 --- a/src/slack/actions.ts +++ b/src/slack/actions.ts @@ -151,7 +151,6 @@ export async function sendSlackMessage( accountId: opts.accountId, token: opts.token, mediaUrl: opts.mediaUrl, - threadTs: opts.threadTs, client: opts.client, threadTs: opts.threadTs, }); diff --git a/src/slack/monitor.tool-result.test.ts b/src/slack/monitor.tool-result.test.ts index d67fe25ab..387f81c73 100644 --- a/src/slack/monitor.tool-result.test.ts +++ b/src/slack/monitor.tool-result.test.ts @@ -601,8 +601,52 @@ describe("monitorSlackProvider tool results", () => { expect(ctx.ParentSessionKey).toBe("agent:support:slack:channel:C1"); }); - it("keeps replies in channel root when message is not threaded", async () => { + it("keeps replies in channel root when message is not threaded (replyToMode off)", async () => { replyMock.mockResolvedValue({ text: "root reply" }); + config = { + messages: { + responsePrefix: "PFX", + ackReaction: "👀", + ackReactionScope: "group-mentions", + }, + slack: { + dm: { enabled: true, policy: "open", allowFrom: ["*"] }, + replyToMode: "off", + }, + }; + + const controller = new AbortController(); + const run = monitorSlackProvider({ + botToken: "bot-token", + appToken: "app-token", + abortSignal: controller.signal, + }); + + await waitForEvent("message"); + const handler = getSlackHandlers()?.get("message"); + if (!handler) throw new Error("Slack message handler not registered"); + + await handler({ + event: { + type: "message", + user: "U1", + text: "hello", + ts: "789", + channel: "C1", + channel_type: "im", + }, + }); + + await flush(); + controller.abort(); + await run; + + expect(sendMock).toHaveBeenCalledTimes(1); + expect(sendMock.mock.calls[0][2]).toMatchObject({ threadTs: undefined }); + }); + + it("threads first reply when replyToMode is first and message is not threaded", async () => { + replyMock.mockResolvedValue({ text: "first reply" }); config = { messages: { responsePrefix: "PFX", @@ -642,7 +686,8 @@ describe("monitorSlackProvider tool results", () => { await run; expect(sendMock).toHaveBeenCalledTimes(1); - expect(sendMock.mock.calls[0][2]).toMatchObject({ threadTs: undefined }); + // First reply starts a thread under the incoming message + expect(sendMock.mock.calls[0][2]).toMatchObject({ threadTs: "789" }); }); it("forces thread replies when replyToId is set", async () => { diff --git a/src/slack/monitor.ts b/src/slack/monitor.ts index 6a25a22b8..b8773316c 100644 --- a/src/slack/monitor.ts +++ b/src/slack/monitor.ts @@ -1110,7 +1110,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) { accountId: account.accountId, runtime, textLimit, - threadTs: effectiveThreadTs, + replyThreadTs: effectiveThreadTs, }); hasRepliedRef.value = true; },