diff --git a/src/agents/tools/slack-actions.e2e.test.ts b/src/agents/tools/slack-actions.e2e.test.ts index fbba80d8f64..a123365cc9f 100644 --- a/src/agents/tools/slack-actions.e2e.test.ts +++ b/src/agents/tools/slack-actions.e2e.test.ts @@ -221,6 +221,21 @@ describe("handleSlackAction", () => { ).rejects.toThrow(/requires content, blocks, or mediaUrl/i); }); + it("rejects blocks combined with mediaUrl", async () => { + const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig; + await expect( + handleSlackAction( + { + action: "sendMessage", + to: "channel:C123", + blocks: [{ type: "divider" }], + mediaUrl: "https://example.com/image.png", + }, + cfg, + ), + ).rejects.toThrow(/does not support blocks with mediaUrl/i); + }); + it("passes blocks JSON to editSlackMessage with empty content", async () => { const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig; editSlackMessage.mockClear(); diff --git a/src/agents/tools/slack-actions.ts b/src/agents/tools/slack-actions.ts index eff7ba45ec8..1350cb62561 100644 --- a/src/agents/tools/slack-actions.ts +++ b/src/agents/tools/slack-actions.ts @@ -185,6 +185,9 @@ export async function handleSlackAction( if (!content && !mediaUrl && !blocks) { throw new Error("Slack sendMessage requires content, blocks, or mediaUrl."); } + if (mediaUrl && blocks) { + throw new Error("Slack sendMessage does not support blocks with mediaUrl."); + } const threadTs = resolveThreadTsFromContext( readStringParam(params, "threadTs"), to, diff --git a/src/channels/plugins/actions/actions.test.ts b/src/channels/plugins/actions/actions.test.ts index 86cd5b12365..563c38ce898 100644 --- a/src/channels/plugins/actions/actions.test.ts +++ b/src/channels/plugins/actions/actions.test.ts @@ -613,6 +613,26 @@ describe("slack actions adapter", () => { expect(handleSlackAction).not.toHaveBeenCalled(); }); + it("rejects send when both blocks and media are provided", async () => { + const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig; + const actions = createSlackActions("slack"); + + await expect( + actions.handleAction?.({ + channel: "slack", + action: "send", + cfg, + params: { + to: "channel:C1", + message: "", + media: "https://example.com/image.png", + blocks: JSON.stringify([{ type: "divider" }]), + }, + }), + ).rejects.toThrow(/does not support blocks with media/i); + expect(handleSlackAction).not.toHaveBeenCalled(); + }); + it("forwards blocks JSON for edit", async () => { const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig; const actions = createSlackActions("slack"); diff --git a/src/plugin-sdk/slack-message-actions.ts b/src/plugin-sdk/slack-message-actions.ts index 8cff504708f..d5a757b80dc 100644 --- a/src/plugin-sdk/slack-message-actions.ts +++ b/src/plugin-sdk/slack-message-actions.ts @@ -41,6 +41,9 @@ export async function handleSlackMessageAction(params: { if (!content && !mediaUrl && !blocks) { throw new Error("Slack send requires message, blocks, or media."); } + if (mediaUrl && blocks) { + throw new Error("Slack send does not support blocks with media."); + } const threadId = readStringParam(actionParams, "threadId"); const replyTo = readStringParam(actionParams, "replyTo"); return await invoke(