fix: cap slack approval update text · openclaw/openclaw@395ad91
steipete
·
2026-04-30
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -74,6 +74,7 @@ Docs: https://docs.openclaw.ai
|
74 | 74 | - Slack/interactive replies: drop overlong Block Kit button URLs while preserving valid callback values, so malformed link buttons no longer make Slack reject the whole interactive reply. Thanks @slackapi. |
75 | 75 | - Slack/commands: truncate native command argument-menu confirmation text to Slack's dialog limit, so long plugin arg names no longer make fallback buttons render invalid Block Kit payloads. Thanks @slackapi. |
76 | 76 | - Slack/exec approvals: cap native approval metadata context to Slack's element and text limits, so large approval details no longer make Slack reject the approval card. Thanks @slackapi. |
| 77 | +- Slack/exec approvals: cap native approval update fallback text to Slack's message limit while preserving the rendered approval blocks, so long commands no longer make resolved or expired approval cards stay stale after `chat.update` rejects `msg_too_long`. Thanks @slackapi. |
77 | 78 | - 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. |
78 | 79 | - 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. |
79 | 80 | - 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. |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | | -import { describe, expect, it } from "vitest"; |
| 1 | +import { describe, expect, it, vi } from "vitest"; |
2 | 2 | import { slackApprovalNativeRuntime } from "./approval-handler.runtime.js"; |
3 | 3 | |
4 | 4 | type SlackPayload = { |
5 | 5 | text: string; |
6 | 6 | blocks?: unknown; |
7 | 7 | }; |
| 8 | +const SLACK_TEXT_LIMIT = 8000; |
8 | 9 | |
9 | 10 | function findSlackActionsBlock(blocks: Array<{ type?: string; elements?: unknown[] }>) { |
10 | 11 | return blocks.find((block) => block.type === "actions"); |
@@ -114,6 +115,53 @@ describe("slackApprovalNativeRuntime", () => {
|
114 | 115 | ).toBe(false); |
115 | 116 | }); |
116 | 117 | |
| 118 | +it("caps resolved update fallback text while preserving approval blocks", async () => { |
| 119 | +const blocks = [ |
| 120 | +{ |
| 121 | +type: "section", |
| 122 | +text: { |
| 123 | +type: "mrkdwn", |
| 124 | +text: "*Command*\n```short preview```", |
| 125 | +}, |
| 126 | +}, |
| 127 | +]; |
| 128 | +const chatUpdate = vi.fn(async (_payload: { text: string; blocks: typeof blocks }) => ({})); |
| 129 | + |
| 130 | +await slackApprovalNativeRuntime.transport.updateEntry?.({ |
| 131 | +cfg: {} as never, |
| 132 | +accountId: "default", |
| 133 | +context: { |
| 134 | +app: { |
| 135 | +client: { |
| 136 | +chat: { |
| 137 | +update: chatUpdate, |
| 138 | +}, |
| 139 | +}, |
| 140 | +}, |
| 141 | +config: {}, |
| 142 | +} as never, |
| 143 | +entry: { |
| 144 | +channelId: "C123", |
| 145 | +messageTs: "1712345678.999999", |
| 146 | +}, |
| 147 | +payload: { |
| 148 | +text: `*Exec approval: Allowed once*\n\n*Command*\n${"a".repeat(9000)}`, |
| 149 | + blocks, |
| 150 | +}, |
| 151 | +phase: "resolved", |
| 152 | +}); |
| 153 | + |
| 154 | +expect(chatUpdate).toHaveBeenCalledWith( |
| 155 | +expect.objectContaining({ |
| 156 | +channel: "C123", |
| 157 | +ts: "1712345678.999999", |
| 158 | +text: expect.stringMatching(/…$/), |
| 159 | + blocks, |
| 160 | +}), |
| 161 | +); |
| 162 | +expect(chatUpdate.mock.calls[0]?.[0].text).toHaveLength(SLACK_TEXT_LIMIT); |
| 163 | +}); |
| 164 | + |
117 | 165 | it("keeps pending metadata context within Slack Block Kit limits", async () => { |
118 | 166 | const payload = (await slackApprovalNativeRuntime.presentation.buildPendingPayload({ |
119 | 167 | cfg: {} as never, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -17,8 +17,10 @@ import {
|
17 | 17 | shouldHandleSlackExecApprovalRequest, |
18 | 18 | normalizeSlackApproverId, |
19 | 19 | } from "./exec-approvals.js"; |
| 20 | +import { SLACK_TEXT_LIMIT } from "./limits.js"; |
20 | 21 | import { resolveSlackReplyBlocks } from "./reply-blocks.js"; |
21 | 22 | import { sendMessageSlack } from "./send.js"; |
| 23 | +import { truncateSlackText } from "./truncate.js"; |
22 | 24 | |
23 | 25 | type SlackBlock = Block | KnownBlock; |
24 | 26 | type SlackPendingApproval = { |
@@ -229,7 +231,7 @@ async function updateMessage(params: {
|
229 | 231 | await params.app.client.chat.update({ |
230 | 232 | channel: params.channelId, |
231 | 233 | ts: params.messageTs, |
232 | | -text: params.text, |
| 234 | +text: truncateSlackText(params.text, SLACK_TEXT_LIMIT), |
233 | 235 | blocks: params.blocks, |
234 | 236 | }); |
235 | 237 | } catch (err) { |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。