refactor: dedupe feishu and bluebubbles lowercase helpers

This commit is contained in:
Peter Steinberger
2026-04-07 13:16:01 +01:00
parent ae4f8da94f
commit 88b394ba1b
12 changed files with 54 additions and 39 deletions

View File

@@ -1,3 +1,5 @@
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
export type FeishuGroupSessionScope =
| "group"
| "group_sender"
@@ -50,7 +52,7 @@ export function parseFeishuTargetId(raw: unknown): string | undefined {
if (!withoutProvider) {
return undefined;
}
const lowered = withoutProvider.toLowerCase();
const lowered = normalizeLowercaseStringOrEmpty(withoutProvider);
for (const prefix of ["chat:", "group:", "channel:", "user:", "dm:", "open_id:"]) {
if (lowered.startsWith(prefix)) {
return normalizeText(withoutProvider.slice(prefix.length));
@@ -68,7 +70,7 @@ export function parseFeishuDirectConversationId(raw: unknown): string | undefine
if (!withoutProvider) {
return undefined;
}
const lowered = withoutProvider.toLowerCase();
const lowered = normalizeLowercaseStringOrEmpty(withoutProvider);
for (const prefix of ["user:", "dm:", "open_id:"]) {
if (lowered.startsWith(prefix)) {
return normalizeText(withoutProvider.slice(prefix.length));
@@ -176,8 +178,8 @@ export function buildFeishuModelOverrideParentCandidates(
}
const topicSenderMatch = rawId.match(/^(.+):topic:([^:]+):sender:([^:]+)$/i);
if (topicSenderMatch) {
const chatId = topicSenderMatch[1]?.trim().toLowerCase();
const topicId = topicSenderMatch[2]?.trim().toLowerCase();
const chatId = normalizeLowercaseStringOrEmpty(topicSenderMatch[1]);
const topicId = normalizeLowercaseStringOrEmpty(topicSenderMatch[2]);
if (chatId && topicId) {
return [`${chatId}:topic:${topicId}`, chatId];
}
@@ -185,12 +187,12 @@ export function buildFeishuModelOverrideParentCandidates(
}
const topicMatch = rawId.match(/^(.+):topic:([^:]+)$/i);
if (topicMatch) {
const chatId = topicMatch[1]?.trim().toLowerCase();
const chatId = normalizeLowercaseStringOrEmpty(topicMatch[1]);
return chatId ? [chatId] : [];
}
const senderMatch = rawId.match(/^(.+):sender:([^:]+)$/i);
if (senderMatch) {
const chatId = senderMatch[1]?.trim().toLowerCase();
const chatId = normalizeLowercaseStringOrEmpty(senderMatch[1]);
return chatId ? [chatId] : [];
}
return [];

View File

@@ -42,7 +42,11 @@ export async function listFeishuDirectoryPeersLive(params: {
for (const user of response.data?.items ?? []) {
if (user.open_id) {
const name = user.name || "";
if (!q || user.open_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {
if (
!q ||
normalizeLowercaseStringOrEmpty(user.open_id).includes(q) ||
normalizeLowercaseStringOrEmpty(name).includes(q)
) {
peers.push({
kind: "user",
id: user.open_id,
@@ -95,7 +99,11 @@ export async function listFeishuDirectoryGroupsLive(params: {
for (const chat of response.data?.items ?? []) {
if (chat.chat_id) {
const name = chat.name || "";
if (!q || chat.chat_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {
if (
!q ||
normalizeLowercaseStringOrEmpty(chat.chat_id).includes(q) ||
normalizeLowercaseStringOrEmpty(name).includes(q)
) {
groups.push({
kind: "group",
id: chat.chat_id,

View File

@@ -4,6 +4,7 @@ import { Readable } from "stream";
import type * as Lark from "@larksuiteoapi/node-sdk";
import { mediaKindFromMime } from "openclaw/plugin-sdk/media-runtime";
import { withTempDownloadPath } from "openclaw/plugin-sdk/temp-path";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import type { ClawdbotConfig } from "../runtime-api.js";
import { resolveFeishuRuntimeAccount } from "./accounts.js";
import { createFeishuClient } from "./client.js";
@@ -106,9 +107,8 @@ function readHeaderValue(
if (!headers) {
return undefined;
}
const target = name.toLowerCase();
for (const [key, value] of Object.entries(headers)) {
if (key.toLowerCase() !== target) {
if (normalizeLowercaseStringOrEmpty(key) !== normalizeLowercaseStringOrEmpty(name)) {
continue;
}
if (typeof value === "string" && value.trim()) {
@@ -496,7 +496,7 @@ export async function sendFileFeishu(params: {
export function detectFileType(
fileName: string,
): "opus" | "mp4" | "pdf" | "doc" | "xls" | "ppt" | "stream" {
const ext = path.extname(fileName).toLowerCase();
const ext = normalizeLowercaseStringOrEmpty(path.extname(fileName));
switch (ext) {
case ".opus":
case ".ogg":
@@ -526,7 +526,7 @@ function resolveFeishuOutboundMediaKind(params: { fileName: string; contentType?
msgType: "image" | "file" | "audio" | "media";
} {
const { fileName, contentType } = params;
const ext = path.extname(fileName).toLowerCase();
const ext = normalizeLowercaseStringOrEmpty(path.extname(fileName));
const mimeKind = mediaKindFromMime(contentType);
const isImageExt = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".ico", ".tiff"].includes(

View File

@@ -1,6 +1,7 @@
import fs from "fs";
import path from "path";
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { resolveFeishuAccount } from "./accounts.js";
import { createFeishuClient } from "./client.js";
import { parseFeishuCommentTarget } from "./comment-target.js";
@@ -27,7 +28,7 @@ function normalizePossibleLocalImagePath(text: string | undefined): string | nul
return null;
}
const ext = path.extname(raw).toLowerCase();
const ext = normalizeLowercaseStringOrEmpty(path.extname(raw));
const isImageExt = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".ico", ".tiff"].includes(
ext,
);

View File

@@ -71,7 +71,9 @@ export function resolveFeishuGroupConfig(params: {
}
const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
const matchKey = Object.keys(groups).find((key) => key.toLowerCase() === lowered);
const matchKey = Object.keys(groups).find(
(key) => normalizeOptionalLowercaseString(key) === lowered,
);
if (matchKey) {
return groups[matchKey];
}

View File

@@ -1,3 +1,4 @@
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
import { isRecord } from "./comment-shared.js";
import { normalizeFeishuExternalKey } from "./external-keys.js";
@@ -133,7 +134,7 @@ function renderElement(
return escapeMarkdownText(toStringOrEmpty(element));
}
const tag = toStringOrEmpty(element.tag).toLowerCase();
const tag = normalizeLowercaseStringOrEmpty(toStringOrEmpty(element.tag));
switch (tag) {
case "text":
return renderTextElement(element);

View File

@@ -1,6 +1,7 @@
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import {
convertMarkdownTables,
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "openclaw/plugin-sdk/text-runtime";
import type { ClawdbotConfig } from "../runtime-api.js";
@@ -34,7 +35,7 @@ function shouldFallbackFromReplyTarget(response: { code?: number; msg?: string }
if (response.code !== undefined && WITHDRAWN_REPLY_ERROR_CODES.has(response.code)) {
return true;
}
const msg = response.msg?.toLowerCase() ?? "";
const msg = normalizeLowercaseStringOrEmpty(response.msg);
return msg.includes("withdrawn") || msg.includes("not found");
}