mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 12:57:40 +00:00
fix(slack): apply limit parameter to emoji-list action (#13421)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 67e9b64858
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
This commit is contained in:
@@ -98,6 +98,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Telegram: surface REACTION_INVALID as non-fatal warning. (#14340) Thanks @0xRaini.
|
- Telegram: surface REACTION_INVALID as non-fatal warning. (#14340) Thanks @0xRaini.
|
||||||
- BlueBubbles: fix webhook auth bypass via loopback proxy trust. (#13787) Thanks @coygeek.
|
- BlueBubbles: fix webhook auth bypass via loopback proxy trust. (#13787) Thanks @coygeek.
|
||||||
- Slack: change default replyToMode from "off" to "all". (#14364) Thanks @nm-de.
|
- Slack: change default replyToMode from "off" to "all". (#14364) Thanks @nm-de.
|
||||||
|
- Slack: honor `limit` for `emoji-list` actions across core and extension adapters, with capped emoji-list responses in the Slack action handler. (#4293) Thanks @mcaxtr.
|
||||||
- Slack: detect control commands when channel messages start with bot mention prefixes (for example, `@Bot /new`). (#14142) Thanks @beefiker.
|
- Slack: detect control commands when channel messages start with bot mention prefixes (for example, `@Bot /new`). (#14142) Thanks @beefiker.
|
||||||
- Slack: include thread reply metadata in inbound message footer context (`thread_ts`, `parent_user_id`) while keeping top-level `thread_ts == ts` events unthreaded. (#14625) Thanks @bennewton999.
|
- Slack: include thread reply metadata in inbound message footer context (`thread_ts`, `parent_user_id`) while keeping top-level `thread_ts == ts` events unthreaded. (#14625) Thanks @bennewton999.
|
||||||
- Signal: enforce E.164 validation for the Signal bot account prompt so mistyped numbers are caught early. (#15063) Thanks @Duartemartins.
|
- Signal: enforce E.164 validation for the Signal bot account prompt so mistyped numbers are caught early. (#15063) Thanks @Duartemartins.
|
||||||
|
|||||||
@@ -426,8 +426,9 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === "emoji-list") {
|
if (action === "emoji-list") {
|
||||||
|
const limit = readNumberParam(params, "limit", { integer: true });
|
||||||
return await getSlackRuntime().channel.slack.handleSlackAction(
|
return await getSlackRuntime().channel.slack.handleSlackAction(
|
||||||
{ action: "emojiList", accountId: accountId ?? undefined },
|
{ action: "emojiList", limit, accountId: accountId ?? undefined },
|
||||||
cfg,
|
cfg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,4 +432,26 @@ describe("handleSlackAction", () => {
|
|||||||
const [, , opts] = sendSlackMessage.mock.calls[0] ?? [];
|
const [, , opts] = sendSlackMessage.mock.calls[0] ?? [];
|
||||||
expect(opts?.token).toBe("xoxp-1");
|
expect(opts?.token).toBe("xoxp-1");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("returns all emojis when no limit is provided", async () => {
|
||||||
|
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
|
||||||
|
const emojiMap = { wave: "url1", smile: "url2", heart: "url3" };
|
||||||
|
listSlackEmojis.mockResolvedValueOnce({ ok: true, emoji: emojiMap });
|
||||||
|
const result = await handleSlackAction({ action: "emojiList" }, cfg);
|
||||||
|
const payload = result.details as { ok: boolean; emojis: { emoji: Record<string, string> } };
|
||||||
|
expect(payload.ok).toBe(true);
|
||||||
|
expect(Object.keys(payload.emojis.emoji)).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies limit to emoji-list results", async () => {
|
||||||
|
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
|
||||||
|
const emojiMap = { wave: "url1", smile: "url2", heart: "url3", fire: "url4", star: "url5" };
|
||||||
|
listSlackEmojis.mockResolvedValueOnce({ ok: true, emoji: emojiMap });
|
||||||
|
const result = await handleSlackAction({ action: "emojiList", limit: 2 }, cfg);
|
||||||
|
const payload = result.details as { ok: boolean; emojis: { emoji: Record<string, string> } };
|
||||||
|
expect(payload.ok).toBe(true);
|
||||||
|
const emojiKeys = Object.keys(payload.emojis.emoji);
|
||||||
|
expect(emojiKeys).toHaveLength(2);
|
||||||
|
expect(emojiKeys.every((k) => k in emojiMap)).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,13 @@ import {
|
|||||||
} from "../../slack/actions.js";
|
} from "../../slack/actions.js";
|
||||||
import { parseSlackTarget, resolveSlackChannelId } from "../../slack/targets.js";
|
import { parseSlackTarget, resolveSlackChannelId } from "../../slack/targets.js";
|
||||||
import { withNormalizedTimestamp } from "../date-time.js";
|
import { withNormalizedTimestamp } from "../date-time.js";
|
||||||
import { createActionGate, jsonResult, readReactionParams, readStringParam } from "./common.js";
|
import {
|
||||||
|
createActionGate,
|
||||||
|
jsonResult,
|
||||||
|
readNumberParam,
|
||||||
|
readReactionParams,
|
||||||
|
readStringParam,
|
||||||
|
} from "./common.js";
|
||||||
|
|
||||||
const messagingActions = new Set(["sendMessage", "editMessage", "deleteMessage", "readMessages"]);
|
const messagingActions = new Set(["sendMessage", "editMessage", "deleteMessage", "readMessages"]);
|
||||||
|
|
||||||
@@ -305,8 +311,18 @@ export async function handleSlackAction(
|
|||||||
if (!isActionEnabled("emojiList")) {
|
if (!isActionEnabled("emojiList")) {
|
||||||
throw new Error("Slack emoji list is disabled.");
|
throw new Error("Slack emoji list is disabled.");
|
||||||
}
|
}
|
||||||
const emojis = readOpts ? await listSlackEmojis(readOpts) : await listSlackEmojis();
|
const result = readOpts ? await listSlackEmojis(readOpts) : await listSlackEmojis();
|
||||||
return jsonResult({ ok: true, emojis });
|
const limit = readNumberParam(params, "limit", { integer: true });
|
||||||
|
if (limit != null && limit > 0 && result.emoji != null) {
|
||||||
|
const entries = Object.entries(result.emoji).toSorted(([a], [b]) => a.localeCompare(b));
|
||||||
|
if (entries.length > limit) {
|
||||||
|
return jsonResult({
|
||||||
|
ok: true,
|
||||||
|
emojis: { ...result, emoji: Object.fromEntries(entries.slice(0, limit)) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jsonResult({ ok: true, emojis: result });
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Unknown action: ${action}`);
|
throw new Error(`Unknown action: ${action}`);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { createSlackActions } from "./slack.actions.js";
|
import { createSlackActions } from "./slack.actions.js";
|
||||||
|
|
||||||
@@ -9,6 +9,10 @@ vi.mock("../../agents/tools/slack-actions.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe("slack actions adapter", () => {
|
describe("slack actions adapter", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
handleSlackAction.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("forwards threadId for read", async () => {
|
it("forwards threadId for read", async () => {
|
||||||
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
|
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
|
||||||
const actions = createSlackActions("slack");
|
const actions = createSlackActions("slack");
|
||||||
@@ -30,4 +34,24 @@ describe("slack actions adapter", () => {
|
|||||||
threadId: "171234.567",
|
threadId: "171234.567",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("forwards normalized limit for emoji-list", async () => {
|
||||||
|
const cfg = { channels: { slack: { botToken: "tok" } } } as OpenClawConfig;
|
||||||
|
const actions = createSlackActions("slack");
|
||||||
|
|
||||||
|
await actions.handleAction?.({
|
||||||
|
channel: "slack",
|
||||||
|
action: "emoji-list",
|
||||||
|
cfg,
|
||||||
|
params: {
|
||||||
|
limit: "2.9",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [params] = handleSlackAction.mock.calls[0] ?? [];
|
||||||
|
expect(params).toMatchObject({
|
||||||
|
action: "emojiList",
|
||||||
|
limit: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -210,8 +210,9 @@ export function createSlackActions(providerId: string): ChannelMessageActionAdap
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === "emoji-list") {
|
if (action === "emoji-list") {
|
||||||
|
const limit = readNumberParam(params, "limit", { integer: true });
|
||||||
return await handleSlackAction(
|
return await handleSlackAction(
|
||||||
{ action: "emojiList", accountId: accountId ?? undefined },
|
{ action: "emojiList", limit, accountId: accountId ?? undefined },
|
||||||
cfg,
|
cfg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user