mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 10:27:38 +00:00
Slack: support blocks in plugin send action
This commit is contained in:
@@ -526,4 +526,71 @@ describe("slack actions adapter", () => {
|
|||||||
limit: 2,
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,27 @@ type SlackActionInvoke = (
|
|||||||
toolContext?: ChannelMessageActionContext["toolContext"],
|
toolContext?: ChannelMessageActionContext["toolContext"],
|
||||||
) => Promise<AgentToolResult<unknown>>;
|
) => 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: {
|
export async function handleSlackMessageAction(params: {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
ctx: ChannelMessageActionContext;
|
ctx: ChannelMessageActionContext;
|
||||||
@@ -28,18 +49,23 @@ export async function handleSlackMessageAction(params: {
|
|||||||
if (action === "send") {
|
if (action === "send") {
|
||||||
const to = readStringParam(actionParams, "to", { required: true });
|
const to = readStringParam(actionParams, "to", { required: true });
|
||||||
const content = readStringParam(actionParams, "message", {
|
const content = readStringParam(actionParams, "message", {
|
||||||
required: true,
|
required: false,
|
||||||
allowEmpty: true,
|
allowEmpty: true,
|
||||||
});
|
});
|
||||||
const mediaUrl = readStringParam(actionParams, "media", { trim: false });
|
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 threadId = readStringParam(actionParams, "threadId");
|
||||||
const replyTo = readStringParam(actionParams, "replyTo");
|
const replyTo = readStringParam(actionParams, "replyTo");
|
||||||
return await invoke(
|
return await invoke(
|
||||||
{
|
{
|
||||||
action: "sendMessage",
|
action: "sendMessage",
|
||||||
to,
|
to,
|
||||||
content,
|
content: content ?? "",
|
||||||
mediaUrl: mediaUrl ?? undefined,
|
mediaUrl: mediaUrl ?? undefined,
|
||||||
|
blocks,
|
||||||
accountId,
|
accountId,
|
||||||
threadTs: threadId ?? replyTo ?? undefined,
|
threadTs: threadId ?? replyTo ?? undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user