fix: cap slack block fallback text

This commit is contained in:
Peter Steinberger
2026-04-30 05:06:35 +01:00
parent c316dbfc4a
commit 30774786f1
3 changed files with 37 additions and 1 deletions

View File

@@ -77,6 +77,7 @@ Docs: https://docs.openclaw.ai
- Slack/commands: cap native command argument-menu fallback rows to Slack's message block limit, so large plugin choice lists no longer make Slack reject the generated menu. Thanks @slackapi.
- Slack/commands: drop fallback command argument buttons whose encoded values exceed Slack's button-value limit, so one oversized plugin choice no longer makes Slack reject the whole menu. Thanks @slackapi.
- Slack/messages: merge message-tool presentation and interactive blocks on Slack sends, so buttons and selects are no longer dropped when a structured message body is also present. Thanks @slackapi.
- Slack/messages: cap Block Kit fallback text to Slack's send limit while preserving the rendered blocks, so long context fallbacks no longer make rich Slack messages fail with `msg_too_long`. Thanks @slackapi.
- Channels/WhatsApp: require Baileys outbound message ids before marking auto-replies delivered, so transcript text and ack reactions no longer make failed group replies look sent. Fixes #49225. Thanks @TinyTb.
- CLI/update: scope packaged Node compile caches by OpenClaw version and install metadata, so global installs no longer reuse stale compiled chunks after package updates. Thanks @pashpashpash.
- Channels/Voice call: keep pre-auth webhook in-flight limiting active when socket remote address metadata is missing, so slow-body requests from stripped-IP proxy paths still share the fallback bucket. (#74453) Thanks @davidangularme.

View File

@@ -4,6 +4,7 @@ import { createSlackSendTestClient, installSlackBlockTestMocks } from "./blocks.
installSlackBlockTestMocks();
const { sendMessageSlack } = await import("./send.js");
const SLACK_TEST_CFG = { channels: { slack: { botToken: "xoxb-test" } } };
const SLACK_TEXT_LIMIT = 8000;
describe("sendMessageSlack NO_REPLY guard", () => {
it("suppresses NO_REPLY text before any Slack API call", async () => {
@@ -170,6 +171,36 @@ describe("sendMessageSlack blocks", () => {
);
});
it("caps long fallback text while preserving blocks", async () => {
const client = createSlackSendTestClient();
const longContextText = "a".repeat(3000);
const blocks = [
{
type: "context",
elements: [
{ type: "mrkdwn", text: longContextText },
{ type: "mrkdwn", text: longContextText },
{ type: "mrkdwn", text: longContextText },
],
},
];
await sendMessageSlack("channel:C123", "", {
token: "xoxb-test",
cfg: SLACK_TEST_CFG,
client,
blocks,
});
expect(client.chat.postMessage).toHaveBeenCalledWith(
expect.objectContaining({
text: expect.stringMatching(/…$/),
blocks,
}),
);
expect(client.chat.postMessage.mock.calls[0]?.[0].text).toHaveLength(SLACK_TEXT_LIMIT);
});
it("rejects blocks combined with mediaUrl", async () => {
const client = createSlackSendTestClient();
await expect(

View File

@@ -26,6 +26,7 @@ import { SLACK_TEXT_LIMIT } from "./limits.js";
import { loadOutboundMediaFromUrl } from "./runtime-api.js";
import { parseSlackTarget } from "./targets.js";
import { resolveSlackBotToken } from "./token.js";
import { truncateSlackText } from "./truncate.js";
const SLACK_UPLOAD_SSRF_POLICY = {
allowedHostnames: ["*.slack.com", "*.slack-edge.com", "*.slack-files.com"],
allowRfc2544BenchmarkRange: true,
@@ -411,7 +412,10 @@ async function sendMessageSlackQueued(params: {
if (opts.mediaUrl) {
throw new Error("Slack send does not support blocks with mediaUrl");
}
const fallbackText = trimmedMessage || buildSlackBlocksFallbackText(blocks);
const fallbackText = truncateSlackText(
trimmedMessage || buildSlackBlocksFallbackText(blocks),
SLACK_TEXT_LIMIT,
);
const response = await postSlackMessageBestEffort({
client,
channelId,