mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
7df5834511
* fix(slack): cap chat.update edit text at the 4000-char limit, not the 8000 send limit updateMessageSlack truncated the edit text to SLACK_TEXT_LIMIT (8000), but Slack chat.update rejects text longer than 4000 characters with msg_too_long (documented in limits.ts). Every other edit path (actions.ts, edit-text.ts, message-action-dispatch.ts, preview-finalize.ts) uses SLACK_EDIT_TEXT_LIMIT (4000); updateMessageSlack was the lone outlier, so a long question-delivery status edit failed instead of landing. Use the edit limit. * fix(slack): enforce edit text byte limits Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com> * fix(slack): preserve prepared edit text within limits Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com> --------- Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
// Slack plugin module implements truncate behavior.
|
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
|
|
export function truncateSlackText(value: string, max: number): string {
|
|
const trimmed = value.trim();
|
|
if (trimmed.length <= max) {
|
|
return trimmed;
|
|
}
|
|
// Slice on a code-point boundary so a surrogate pair (emoji / astral char)
|
|
// straddling the limit is dropped whole, instead of leaving a lone surrogate
|
|
// half that serializes to an invalid `\uD83D` in the Slack payload.
|
|
if (max <= 1) {
|
|
return sliceUtf16Safe(trimmed, 0, max);
|
|
}
|
|
return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
|
|
}
|
|
|
|
export function countSlackTextUtf8Bytes(value: string): number {
|
|
return Buffer.byteLength(value, "utf8");
|
|
}
|
|
|
|
/** Truncate Slack text without splitting a code point or exceeding a UTF-8 byte limit. */
|
|
export function truncateSlackTextByUtf8Bytes(value: string, maxBytes: number): string {
|
|
const trimmed = value.trim();
|
|
if (maxBytes <= 0) {
|
|
return "";
|
|
}
|
|
if (countSlackTextUtf8Bytes(trimmed) <= maxBytes) {
|
|
return trimmed;
|
|
}
|
|
|
|
const suffix = "…";
|
|
const suffixBytes = countSlackTextUtf8Bytes(suffix);
|
|
const prefixBudget = maxBytes >= suffixBytes ? maxBytes - suffixBytes : maxBytes;
|
|
let prefix = "";
|
|
let prefixBytes = 0;
|
|
for (const character of trimmed) {
|
|
const characterBytes = countSlackTextUtf8Bytes(character);
|
|
if (prefixBytes + characterBytes > prefixBudget) {
|
|
break;
|
|
}
|
|
prefix += character;
|
|
prefixBytes += characterBytes;
|
|
}
|
|
return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
|
|
}
|