refactor: dedupe slack matrix venice lowercase helpers

This commit is contained in:
Peter Steinberger
2026-04-07 14:20:57 +01:00
parent 62a5480808
commit f2b13b0a1a
17 changed files with 45 additions and 24 deletions

View File

@@ -39,7 +39,7 @@ const MATRIX_PLUGIN_NATIVE_DELIVERY_DISABLED = {
function normalizeComparableTarget(value: string): string {
const target = resolveMatrixTargetIdentity(value);
if (!target) {
return value.trim().toLowerCase();
return normalizeLowercaseStringOrEmpty(value);
}
if (target.kind === "user") {
return `user:${normalizeMatrixUserId(target.id)}`;

View File

@@ -1,7 +1,8 @@
import net from "node:net";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
function normalizeHost(host: string): string {
const normalized = host.trim().toLowerCase().replace(/\.+$/, "");
const normalized = normalizeLowercaseStringOrEmpty(host).replace(/\.+$/, "");
return normalized.startsWith("[") && normalized.endsWith("]")
? normalized.slice(1, -1)
: normalized;

View File

@@ -1,3 +1,4 @@
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import type { LocationMessageEventContent } from "../sdk.js";
import { formatLocationText, toLocationContext, type NormalizedLocation } from "./runtime-api.js";
import { EventType } from "./types.js";
@@ -18,7 +19,7 @@ function parseGeoUri(value: string): GeoUriParams | null {
if (!trimmed) {
return null;
}
if (!trimmed.toLowerCase().startsWith("geo:")) {
if (!normalizeLowercaseStringOrEmpty(trimmed).startsWith("geo:")) {
return null;
}
const payload = trimmed.slice(4);
@@ -42,7 +43,7 @@ function parseGeoUri(value: string): GeoUriParams | null {
const eqIndex = segment.indexOf("=");
const rawKey = eqIndex === -1 ? segment : segment.slice(0, eqIndex);
const rawValue = eqIndex === -1 ? "" : segment.slice(eqIndex + 1);
const key = rawKey.trim().toLowerCase();
const key = normalizeLowercaseStringOrEmpty(rawKey);
if (!key) {
continue;
}

View File

@@ -1,4 +1,5 @@
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import { resolveMatrixAccountConfig } from "./matrix/accounts.js";
import {
bootstrapMatrixVerification,
@@ -433,7 +434,7 @@ export async function handleMatrixAction(
}
if (action === "verificationStart") {
const methodRaw = readStringParam(params, "method");
const method = methodRaw?.trim().toLowerCase();
const method = normalizeOptionalLowercaseString(methodRaw);
if (method && method !== "sas") {
throw new Error(
"Matrix verificationStart only supports method=sas; use verificationGenerateQr/verificationScanQr for QR flows.",

View File

@@ -36,7 +36,7 @@ function extractSlackSessionKind(
}
function normalizeComparableTarget(value: string): string {
return value.trim().toLowerCase();
return normalizeLowercaseStringOrEmpty(value);
}
function normalizeSlackThreadMatchKey(threadId?: string): string {

View File

@@ -1,3 +1,4 @@
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { resolveSlackAccount } from "./accounts.js";
import { createSlackWebClient } from "./client.js";
import { normalizeAllowListLower } from "./monitor/allow-list.js";
@@ -36,7 +37,7 @@ export async function resolveSlackChannelType(params: {
const channelKeys = Object.keys(account.channels ?? {});
if (
channelKeys.some((key) => {
const normalized = key.trim().toLowerCase();
const normalized = normalizeLowercaseStringOrEmpty(key);
return (
normalized === channelIdLower ||
normalized === `channel:${channelIdLower}` ||

View File

@@ -2,6 +2,10 @@ import type {
ChannelDirectoryEntry,
DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "openclaw/plugin-sdk/text-runtime";
import { resolveSlackAccount } from "./accounts.js";
import { createSlackWebClient } from "./client.js";
@@ -42,7 +46,7 @@ function resolveReadToken(params: DirectoryConfigParams): string | undefined {
}
function normalizeQuery(value?: string | null): string {
return value?.trim().toLowerCase() ?? "";
return normalizeLowercaseStringOrEmpty(value);
}
function buildUserRank(user: SlackUser): number {
@@ -89,7 +93,7 @@ export async function listSlackDirectoryPeersLive(
const handle = member.name;
const email = member.profile?.email;
const candidates = [name, handle, email]
.map((item) => item?.trim().toLowerCase())
.map((item) => normalizeOptionalLowercaseString(item))
.filter(Boolean);
if (!query) {
return true;
@@ -153,7 +157,7 @@ export async function listSlackDirectoryGroupsLive(
} while (cursor);
const filtered = channels.filter((channel) => {
const name = channel.name?.trim().toLowerCase();
const name = normalizeOptionalLowercaseString(channel.name);
if (!query) {
return true;
}

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { resolveDefaultSlackAccountId, resolveSlackAccount } from "./accounts.js";
const SLACK_BUTTON_MAX_ITEMS = 5;
@@ -154,7 +155,7 @@ function resolveInteractiveRepliesFromCapabilities(capabilities: unknown): boole
}
if (Array.isArray(capabilities)) {
return capabilities.some(
(entry) => String(entry).trim().toLowerCase() === "interactivereplies",
(entry) => normalizeLowercaseStringOrEmpty(String(entry)) === "interactivereplies",
);
}
if (typeof capabilities === "object") {

View File

@@ -8,6 +8,7 @@ import {
normalizeStringEntries,
normalizeStringEntriesLower,
} from "openclaw/plugin-sdk/string-normalization-runtime";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
const SLACK_SLUG_CACHE_MAX = 512;
const slackSlugCache = new Map<string, string>();
@@ -38,7 +39,7 @@ export function normalizeAllowListLower(list?: Array<string | number>) {
}
export function normalizeSlackAllowOwnerEntry(entry: string): string | undefined {
const trimmed = entry.trim().toLowerCase();
const trimmed = normalizeOptionalLowercaseString(entry);
if (!trimmed || trimmed === "*") {
return undefined;
}

View File

@@ -1,3 +1,4 @@
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import type { SlackMessageEvent } from "../types.js";
export function inferSlackChannelType(
@@ -23,7 +24,7 @@ export function normalizeSlackChannelType(
channelType?: string | null,
channelId?: string | null,
): SlackMessageEvent["channel_type"] {
const normalized = channelType?.trim().toLowerCase();
const normalized = normalizeOptionalLowercaseString(channelType);
const inferred = inferSlackChannelType(channelId);
if (
normalized === "im" ||

View File

@@ -5,6 +5,7 @@ import type { FetchLike } from "openclaw/plugin-sdk/media-runtime";
import { fetchRemoteMedia } from "openclaw/plugin-sdk/media-runtime";
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import type { SlackAttachment, SlackFile } from "../types.js";
function isSlackHostname(hostname: string): boolean {
@@ -239,7 +240,7 @@ export async function resolveSlackMedia(params: {
const isExpectedHtml =
fileMime === "text/html" || fileName.endsWith(".html") || fileName.endsWith(".htm");
if (!isExpectedHtml) {
const detectedMime = fetched.contentType?.split(";")[0]?.trim().toLowerCase();
const detectedMime = normalizeOptionalLowercaseString(fetched.contentType?.split(";")[0]);
if (detectedMime === "text/html" || looksLikeHtmlBuffer(fetched.buffer)) {
return null;
}

View File

@@ -18,6 +18,7 @@ import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-pay
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import { reactSlackMessage, removeSlackReaction } from "../../actions.js";
import { createSlackDraftStream } from "../../draft-stream.js";
import { normalizeSlackOutboundText } from "../../format.js";
@@ -161,11 +162,11 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
allowFrom: ctx.allowFrom,
normalizeEntry: normalizeSlackAllowOwnerEntry,
});
const senderRecipient = message.user?.trim().toLowerCase();
const senderRecipient = normalizeOptionalLowercaseString(message.user);
const skipMainUpdate =
pinnedMainDmOwner &&
senderRecipient &&
pinnedMainDmOwner.trim().toLowerCase() !== senderRecipient;
normalizeOptionalLowercaseString(pinnedMainDmOwner) !== senderRecipient;
if (skipMainUpdate) {
logVerbose(
`slack: skip main-session last route for ${senderRecipient} (pinned owner ${pinnedMainDmOwner})`,

View File

@@ -11,7 +11,7 @@ import {
} from "openclaw/plugin-sdk/config-runtime";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
import { chunkItems } from "openclaw/plugin-sdk/text-runtime";
import { chunkItems, normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import type { ResolvedSlackAccount } from "../accounts.js";
import { truncateSlackText } from "../truncate.js";
import { resolveSlackAllowListMatch, resolveSlackUserAllowed } from "./allow-list.js";
@@ -769,7 +769,7 @@ export async function registerSlackMonitorSlashCommands(params: {
await ack({ options: [] });
return;
}
const query = typedBody.value?.trim().toLowerCase() ?? "";
const query = normalizeLowercaseStringOrEmpty(typedBody.value);
const options = entry.choices
.filter((choice) => !query || choice.label.toLowerCase().includes(query))
.slice(0, SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX)

View File

@@ -1,4 +1,5 @@
import type { WebClient } from "@slack/web-api";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { createSlackWebClient } from "./client.js";
import {
collectSlackCursorItems,
@@ -81,7 +82,7 @@ function resolveByName(
name: string,
channels: SlackChannelLookup[],
): SlackChannelLookup | undefined {
const target = name.trim().toLowerCase();
const target = normalizeLowercaseStringOrEmpty(name);
if (!target) {
return undefined;
}

View File

@@ -16,7 +16,10 @@ import {
type OpenClawConfig,
} from "openclaw/plugin-sdk/setup-runtime";
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
} from "openclaw/plugin-sdk/text-runtime";
import { inspectSlackAccount } from "./account-inspect.js";
import { resolveSlackAccount } from "./accounts.js";
import {
@@ -39,7 +42,7 @@ function hasSlackInteractiveRepliesConfig(cfg: OpenClawConfig, accountId: string
const capabilities = resolveSlackAccount({ cfg, accountId }).config.capabilities;
if (Array.isArray(capabilities)) {
return capabilities.some(
(entry) => String(entry).trim().toLowerCase() === "interactivereplies",
(entry) => normalizeLowercaseStringOrEmpty(String(entry)) === "interactivereplies",
);
}
if (!capabilities || typeof capabilities !== "object") {
@@ -57,7 +60,9 @@ function setSlackInteractiveReplies(
const nextCapabilities = Array.isArray(capabilities)
? interactiveReplies
? [...new Set([...capabilities, "interactiveReplies"])]
: capabilities.filter((entry) => String(entry).trim().toLowerCase() !== "interactivereplies")
: capabilities.filter(
(entry) => normalizeLowercaseStringOrEmpty(String(entry)) !== "interactivereplies",
)
: {
...((capabilities && typeof capabilities === "object" ? capabilities : {}) as Record<
string,

View File

@@ -1,3 +1,4 @@
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import {
mapStreamingModeToSlackLegacyDraftStreamMode,
resolveSlackNativeStreaming,
@@ -14,7 +15,7 @@ export function resolveSlackStreamMode(raw: unknown): SlackStreamMode {
if (typeof raw !== "string") {
return DEFAULT_STREAM_MODE;
}
const normalized = raw.trim().toLowerCase();
const normalized = normalizeLowercaseStringOrEmpty(raw);
if (normalized === "replace" || normalized === "status_final" || normalized === "append") {
return normalized;
}

View File

@@ -1,12 +1,13 @@
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import { applyXaiModelCompat } from "openclaw/plugin-sdk/provider-tools";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { applyVeniceConfig, VENICE_DEFAULT_MODEL_REF } from "./onboard.js";
import { buildVeniceProvider } from "./provider-catalog.js";
const PROVIDER_ID = "venice";
function isXaiBackedVeniceModel(modelId: string): boolean {
return modelId.trim().toLowerCase().includes("grok");
return normalizeLowercaseStringOrEmpty(modelId).includes("grok");
}
export default defineSingleProviderPluginEntry({