From 6c5064b43753e5819ea1b2be08b651eadffabe32 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Fri, 3 Apr 2026 14:26:24 -0500 Subject: [PATCH] fix: honor slack default hook account --- extensions/slack/src/outbound-adapter.ts | 9 +++++- extensions/slack/src/outbound-hooks.test.ts | 32 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/extensions/slack/src/outbound-adapter.ts b/extensions/slack/src/outbound-adapter.ts index 49336b4ca0c..a367acdfa04 100644 --- a/extensions/slack/src/outbound-adapter.ts +++ b/extensions/slack/src/outbound-adapter.ts @@ -21,6 +21,7 @@ import { parseSlackBlocksInput } from "./blocks-input.js"; import { buildSlackInteractiveBlocks, type SlackBlock } from "./blocks-render.js"; import { compileSlackInteractiveReplies } from "./interactive-replies.js"; import { SLACK_TEXT_LIMIT } from "./limits.js"; +import { resolveSlackAccount } from "./accounts.js"; import { sendMessageSlack, type SlackSendIdentity } from "./send.js"; const SLACK_MAX_BLOCKS = 50; @@ -50,6 +51,7 @@ function resolveSlackSendIdentity(identity?: OutboundIdentity): SlackSendIdentit } async function applySlackMessageSendingHooks(params: { + cfg: NonNullable[2]>["cfg"]; to: string; text: string; threadTs?: string; @@ -60,6 +62,10 @@ async function applySlackMessageSendingHooks(params: { if (!hookRunner?.hasHooks("message_sending")) { return { cancelled: false, text: params.text }; } + const account = resolveSlackAccount({ + cfg: params.cfg, + accountId: params.accountId, + }); const hookResult = await hookRunner.runMessageSending( { to: params.to, @@ -70,7 +76,7 @@ async function applySlackMessageSendingHooks(params: { ...(params.mediaUrl ? { mediaUrl: params.mediaUrl } : {}), }, }, - { channelId: "slack", accountId: params.accountId ?? undefined }, + { channelId: "slack", accountId: account.accountId }, ); if (hookResult?.cancel) { return { cancelled: true, text: params.text }; @@ -101,6 +107,7 @@ async function sendSlackOutboundMessage(params: { const threadTs = params.replyToId ?? (params.threadId != null ? String(params.threadId) : undefined); const hookResult = await applySlackMessageSendingHooks({ + cfg: params.cfg, to: params.to, text: params.text, threadTs, diff --git a/extensions/slack/src/outbound-hooks.test.ts b/extensions/slack/src/outbound-hooks.test.ts index c7e81b7f8da..8146a50c48b 100644 --- a/extensions/slack/src/outbound-hooks.test.ts +++ b/extensions/slack/src/outbound-hooks.test.ts @@ -140,6 +140,38 @@ describe("slack outbound hook wiring", () => { expectSlackSendCalledWith("hello"); }); + it("uses configured defaultAccount for hook context when accountId is omitted", async () => { + const mockRunner = { + hasHooks: vi.fn().mockReturnValue(true), + runMessageSending: vi.fn().mockResolvedValue(undefined), + }; + getGlobalHookRunnerMock.mockReturnValue(mockRunner); + + const sendText = slackOutbound.sendText as NonNullable; + await sendText({ + cfg: { + channels: { + slack: { + defaultAccount: "work", + accounts: { + work: { + botToken: "xoxb-work", + }, + }, + }, + }, + } as OpenClawConfig, + to: "C123", + text: "hello", + replyToId: "1111.2222", + }); + + expect(mockRunner.runMessageSending).toHaveBeenCalledWith( + { to: "C123", content: "hello", metadata: { threadTs: "1111.2222", channelId: "C123" } }, + { channelId: "slack", accountId: "work" }, + ); + }); + it("cancels send when hook returns cancel:true", async () => { const mockRunner = { hasHooks: vi.fn().mockReturnValue(true),