Slack: support blocks in plugin send action

This commit is contained in:
Colin
2026-02-16 12:11:36 -05:00
committed by Peter Steinberger
parent 08bc1dce6a
commit 3912a2264b
2 changed files with 95 additions and 2 deletions

View File

@@ -526,4 +526,71 @@ describe("slack actions adapter", () => {
limit: 2,
});
});
it("forwards blocks JSON for send", async () => {
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
const actions = createSlackActions("slack");
await actions.handleAction?.({
channel: "slack",
action: "send",
cfg,
params: {
to: "channel:C1",
message: "",
blocks: JSON.stringify([{ type: "divider" }]),
},
});
const [params] = handleSlackAction.mock.calls[0] ?? [];
expect(params).toMatchObject({
action: "sendMessage",
to: "channel:C1",
content: "",
blocks: [{ type: "divider" }],
});
});
it("forwards blocks arrays for send", async () => {
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
const actions = createSlackActions("slack");
await actions.handleAction?.({
channel: "slack",
action: "send",
cfg,
params: {
to: "channel:C1",
message: "",
blocks: [{ type: "section", text: { type: "mrkdwn", text: "hi" } }],
},
});
const [params] = handleSlackAction.mock.calls[0] ?? [];
expect(params).toMatchObject({
action: "sendMessage",
to: "channel:C1",
content: "",
blocks: [{ type: "section", text: { type: "mrkdwn", text: "hi" } }],
});
});
it("rejects invalid blocks JSON for send", 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: "",
blocks: "{bad-json",
},
}),
).rejects.toThrow(/blocks must be valid JSON/i);
expect(handleSlackAction).not.toHaveBeenCalled();
});
});

View File

@@ -8,6 +8,27 @@ type SlackActionInvoke = (
toolContext?: ChannelMessageActionContext["toolContext"],
) => Promise<AgentToolResult<unknown>>;
function readSlackBlocksParam(actionParams: Record<string, unknown>) {
const raw = actionParams.blocks;
if (raw == null) {
return undefined;
}
const parsed =
typeof raw === "string"
? (() => {
try {
return JSON.parse(raw);
} catch {
throw new Error("blocks must be valid JSON");
}
})()
: raw;
if (!Array.isArray(parsed)) {
throw new Error("blocks must be an array");
}
return parsed as Record<string, unknown>[];
}
export async function handleSlackMessageAction(params: {
providerId: string;
ctx: ChannelMessageActionContext;
@@ -28,18 +49,23 @@ export async function handleSlackMessageAction(params: {
if (action === "send") {
const to = readStringParam(actionParams, "to", { required: true });
const content = readStringParam(actionParams, "message", {
required: true,
required: false,
allowEmpty: true,
});
const mediaUrl = readStringParam(actionParams, "media", { trim: false });
const blocks = readSlackBlocksParam(actionParams);
if (!content && !mediaUrl && !blocks) {
throw new Error("Slack send requires message, blocks, or media.");
}
const threadId = readStringParam(actionParams, "threadId");
const replyTo = readStringParam(actionParams, "replyTo");
return await invoke(
{
action: "sendMessage",
to,
content,
content: content ?? "",
mediaUrl: mediaUrl ?? undefined,
blocks,
accountId,
threadTs: threadId ?? replyTo ?? undefined,
},