mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:00:44 +00:00
fix: preserve discord unicode channel labels
This commit is contained in:
@@ -37,6 +37,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Proxy/audio: convert standard `FormData` bodies before proxy-backed undici fetches, so audio transcription and multipart uploads no longer send `[object FormData]` when `HTTP_PROXY` or `HTTPS_PROXY` is configured. Fixes #48554. Thanks @dco5.
|
||||
- Discord: allow explicitly configured ack reactions in tool-only guild channels while keeping automatic lifecycle/status reactions suppressed. Fixes #74922. Thanks @samvilian and @BlueBirdBack.
|
||||
- Discord: preserve attachment and sticker filenames when saving inbound media, so agents can see human-readable file names instead of only UUID-based paths. Fixes #59744. Thanks @xela92 and @rockcent.
|
||||
- Discord: preserve non-ASCII channel names in session display labels while keeping allowlist matching on the existing ASCII slug contract. Thanks @swjeong9.
|
||||
- Gateway/diagnostics: include a bounded redacted startup error message in stability bundles, so crash-loop reports identify the failing plugin or contract without exposing secrets. Refs #75797. Thanks @ymebosma.
|
||||
- Gateway/pricing: abort in-flight model pricing catalog fetches when Gateway shutdown stops the refresh loop, and avoid post-stop cache writes or refresh timers. Fixes #72208. Thanks @rzcq.
|
||||
- Codex/app-server: make startup retry cleanup ownership-aware so concurrent Codex lanes cannot close another lane's freshly restarted shared app-server client. Thanks @vincentkoc.
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
type ComponentInteractionContext,
|
||||
type DiscordChannelContext,
|
||||
} from "./agent-components.types.js";
|
||||
import { normalizeDiscordSlug } from "./allow-list.js";
|
||||
import { normalizeDiscordDisplaySlug, normalizeDiscordSlug } from "./allow-list.js";
|
||||
import { resolveDiscordChannelInfoSafe } from "./channel-access.js";
|
||||
|
||||
function formatUsername(user: { username: string; discriminator?: string | null }): string {
|
||||
@@ -72,6 +72,7 @@ export function resolveDiscordChannelContext(
|
||||
const channelInfo = resolveDiscordChannelInfoSafe(channel);
|
||||
const channelName = channelInfo.name;
|
||||
const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
|
||||
const displayChannelSlug = channelName ? normalizeDiscordDisplaySlug(channelName) : "";
|
||||
const channelType = channelInfo.type;
|
||||
const isThread = isThreadChannelType(channelType);
|
||||
|
||||
@@ -86,7 +87,16 @@ export function resolveDiscordChannelContext(
|
||||
}
|
||||
}
|
||||
|
||||
return { channelName, channelSlug, channelType, isThread, parentId, parentName, parentSlug };
|
||||
return {
|
||||
channelName,
|
||||
channelSlug,
|
||||
displayChannelSlug,
|
||||
channelType,
|
||||
isThread,
|
||||
parentId,
|
||||
parentName,
|
||||
parentSlug,
|
||||
};
|
||||
}
|
||||
|
||||
export async function resolveComponentInteractionContext(params: {
|
||||
|
||||
@@ -129,8 +129,8 @@ export async function dispatchDiscordComponentEvent(params: {
|
||||
const senderUsername = interactionCtx.user.username;
|
||||
const senderTag = formatDiscordUserTag(interactionCtx.user);
|
||||
const groupChannel =
|
||||
!interactionCtx.isDirectMessage && channelCtx.channelSlug
|
||||
? `#${channelCtx.channelSlug}`
|
||||
!interactionCtx.isDirectMessage && channelCtx.displayChannelSlug
|
||||
? `#${channelCtx.displayChannelSlug}`
|
||||
: undefined;
|
||||
const groupSubject = interactionCtx.isDirectMessage ? undefined : groupChannel;
|
||||
const channelConfig = resolveDiscordChannelConfigWithFallback({
|
||||
|
||||
@@ -26,6 +26,7 @@ export type AgentComponentInteraction = AgentComponentMessageInteraction | Modal
|
||||
export type DiscordChannelContext = {
|
||||
channelName: string | undefined;
|
||||
channelSlug: string;
|
||||
displayChannelSlug: string;
|
||||
channelType: number | undefined;
|
||||
isThread: boolean;
|
||||
parentId: string | undefined;
|
||||
|
||||
14
extensions/discord/src/monitor/allow-list.test.ts
Normal file
14
extensions/discord/src/monitor/allow-list.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeDiscordDisplaySlug, normalizeDiscordSlug } from "./allow-list.js";
|
||||
|
||||
describe("discord slug normalization", () => {
|
||||
it("keeps config slugs ASCII-only", () => {
|
||||
expect(normalizeDiscordSlug("\uC2E4\uD5D8")).toBe("");
|
||||
expect(normalizeDiscordSlug("baseline-\uAC80\uC99D")).toBe("baseline");
|
||||
});
|
||||
|
||||
it("preserves Unicode in display slugs", () => {
|
||||
expect(normalizeDiscordDisplaySlug("\uC2E4\uD5D8")).toBe("\uC2E4\uD5D8");
|
||||
expect(normalizeDiscordDisplaySlug("baseline-\uAC80\uC99D")).toBe("baseline-\uAC80\uC99D");
|
||||
});
|
||||
});
|
||||
@@ -94,6 +94,16 @@ export function normalizeDiscordSlug(value: string) {
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
export function normalizeDiscordDisplaySlug(value: string) {
|
||||
return normalizeLowercaseStringOrEmpty(value)
|
||||
.normalize("NFC")
|
||||
.replace(/^#/, "")
|
||||
.replace(/[\s_]+/g, "-")
|
||||
.replace(/[^\p{L}\p{M}\p{N}-]+/gu, "-")
|
||||
.replace(/-{2,}/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
function resolveDiscordAllowListNameMatch(
|
||||
list: DiscordAllowList,
|
||||
candidate: { name?: string; tag?: string },
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveDiscordPreflightChannelContext } from "./message-handler.preflight-channel-context.js";
|
||||
|
||||
describe("resolveDiscordPreflightChannelContext", () => {
|
||||
it("uses Unicode channel names for display without changing config matching slugs", () => {
|
||||
const context = resolveDiscordPreflightChannelContext({
|
||||
isGuildMessage: true,
|
||||
messageChannelId: "channel-1",
|
||||
channelName: "\uC2E4\uD5D8",
|
||||
guildName: "Guild",
|
||||
guildInfo: null,
|
||||
threadChannel: undefined,
|
||||
});
|
||||
|
||||
expect(context.configChannelSlug).toBe("");
|
||||
expect(context.displayChannelSlug).toBe("\uC2E4\uD5D8");
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
normalizeDiscordDisplaySlug,
|
||||
normalizeDiscordSlug,
|
||||
resolveDiscordChannelConfigWithFallback,
|
||||
type DiscordGuildEntryResolved,
|
||||
@@ -19,7 +20,9 @@ export function resolveDiscordPreflightChannelContext(params: {
|
||||
const configChannelName = params.threadParentName ?? params.channelName;
|
||||
const configChannelSlug = configChannelName ? normalizeDiscordSlug(configChannelName) : "";
|
||||
const displayChannelName = threadName ?? params.channelName;
|
||||
const displayChannelSlug = displayChannelName ? normalizeDiscordSlug(displayChannelName) : "";
|
||||
const displayChannelSlug = displayChannelName
|
||||
? normalizeDiscordDisplaySlug(displayChannelName)
|
||||
: "";
|
||||
const guildSlug =
|
||||
params.guildInfo?.slug || (params.guildName ? normalizeDiscordSlug(params.guildName) : "");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user