mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
refactor: dedupe telegram matrix lowercase helpers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
||||
import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js";
|
||||
import { resolveDefaultMatrixAccountId, resolveMatrixAccount } from "./matrix/accounts.js";
|
||||
@@ -287,13 +288,11 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
||||
}
|
||||
|
||||
if (action === "permissions") {
|
||||
const operation = (
|
||||
const operation = normalizeLowercaseStringOrEmpty(
|
||||
readStringParam(params, "operation") ??
|
||||
readStringParam(params, "mode") ??
|
||||
"verification-list"
|
||||
)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
readStringParam(params, "mode") ??
|
||||
"verification-list",
|
||||
);
|
||||
const operationToAction: Record<string, string> = {
|
||||
"encryption-status": "encryptionStatus",
|
||||
"verification-status": "verificationStatus",
|
||||
|
||||
@@ -42,7 +42,7 @@ function normalizeComparableTarget(value: string): string {
|
||||
if (target.kind === "user") {
|
||||
return `user:${normalizeMatrixUserId(target.id)}`;
|
||||
}
|
||||
return `${target.kind.toLowerCase()}:${target.id}`;
|
||||
return `${normalizeLowercaseStringOrEmpty(target.kind)}:${target.id}`;
|
||||
}
|
||||
|
||||
function resolveMatrixNativeTarget(raw: string): string | null {
|
||||
|
||||
@@ -25,7 +25,10 @@ import {
|
||||
createDefaultChannelRuntimeState,
|
||||
} from "openclaw/plugin-sdk/status-helpers";
|
||||
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import { matrixMessageActions } from "./actions.js";
|
||||
import { matrixApprovalCapability } from "./approval-native.js";
|
||||
import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js";
|
||||
@@ -100,7 +103,7 @@ const listMatrixDirectoryPeersFromConfig =
|
||||
if (!raw || raw === "*") {
|
||||
return null;
|
||||
}
|
||||
const lowered = raw.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(raw);
|
||||
const cleaned = lowered.startsWith("user:") ? raw.slice("user:".length).trim() : raw;
|
||||
return cleaned.startsWith("@") ? `user:${cleaned}` : cleaned;
|
||||
},
|
||||
@@ -116,7 +119,7 @@ const listMatrixDirectoryGroupsFromConfig =
|
||||
if (!raw || raw === "*") {
|
||||
return null;
|
||||
}
|
||||
const lowered = raw.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(raw);
|
||||
if (lowered.startsWith("room:") || lowered.startsWith("channel:")) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import { resolveMatrixAuth } from "./matrix/client.js";
|
||||
import { MatrixAuthedHttpClient } from "./matrix/sdk/http-client.js";
|
||||
import { isMatrixQualifiedUserId, normalizeMatrixMessagingTarget } from "./matrix/target-ids.js";
|
||||
@@ -66,7 +69,7 @@ async function resolveMatrixDirectoryContext(params: MatrixDirectoryLiveParams):
|
||||
auth,
|
||||
client: createMatrixDirectoryClient(auth),
|
||||
query,
|
||||
queryLower: query.toLowerCase(),
|
||||
queryLower: normalizeLowercaseStringOrEmpty(query),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -217,7 +220,7 @@ export async function listMatrixDirectoryGroupsLive(
|
||||
|
||||
for (const roomId of rooms) {
|
||||
const name = await fetchMatrixRoomName(client, roomId);
|
||||
if (!name || !name.toLowerCase().includes(queryLower)) {
|
||||
if (!name || !normalizeLowercaseStringOrEmpty(name).includes(queryLower)) {
|
||||
continue;
|
||||
}
|
||||
results.push({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { normalizeAccountId, normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
const MATRIX_SCOPED_ENV_SUFFIXES = [
|
||||
"HOMESERVER",
|
||||
@@ -60,7 +61,7 @@ function decodeMatrixEnvAccountToken(token: string): string | undefined {
|
||||
if (!char || !/[A-Z0-9]/.test(char)) {
|
||||
return undefined;
|
||||
}
|
||||
decoded += char.toLowerCase();
|
||||
decoded += normalizeLowercaseStringOrEmpty(char);
|
||||
index += 1;
|
||||
}
|
||||
const normalized = normalizeOptionalAccountId(decoded);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
export function formatMatrixErrorMessage(err: unknown): string {
|
||||
return formatErrorMessage(err);
|
||||
}
|
||||
|
||||
export function formatMatrixErrorReason(err: unknown): string {
|
||||
return formatMatrixErrorMessage(err).toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(formatMatrixErrorMessage(err));
|
||||
}
|
||||
|
||||
export function isMatrixNotFoundError(err: unknown): boolean {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { isAutoLinkedFileRef } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
isAutoLinkedFileRef,
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { MatrixClient } from "./sdk.js";
|
||||
import { isMatrixQualifiedUserId } from "./target-ids.js";
|
||||
|
||||
@@ -147,7 +150,7 @@ function buildMentionCandidate(raw: string, start: number): MatrixMentionCandida
|
||||
if (!normalized) {
|
||||
return null;
|
||||
}
|
||||
const kind = normalized.raw.toLowerCase() === "@room" ? "room" : "user";
|
||||
const kind = normalizeLowercaseStringOrEmpty(normalized.raw) === "@room" ? "room" : "user";
|
||||
const base: MatrixMentionCandidate = {
|
||||
raw: normalized.raw,
|
||||
start,
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type AllowlistMatch,
|
||||
} from "openclaw/plugin-sdk/allow-from";
|
||||
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-normalization-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
function normalizeAllowList(list?: Array<string | number>) {
|
||||
return normalizeStringEntries(list);
|
||||
@@ -14,19 +15,19 @@ function normalizeMatrixUser(raw?: string | null): string {
|
||||
return "";
|
||||
}
|
||||
if (!value.startsWith("@") || !value.includes(":")) {
|
||||
return value.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(value);
|
||||
}
|
||||
const withoutAt = value.slice(1);
|
||||
const splitIndex = withoutAt.indexOf(":");
|
||||
if (splitIndex === -1) {
|
||||
return value.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(value);
|
||||
}
|
||||
const localpart = withoutAt.slice(0, splitIndex).toLowerCase();
|
||||
const server = withoutAt.slice(splitIndex + 1).toLowerCase();
|
||||
const localpart = normalizeLowercaseStringOrEmpty(withoutAt.slice(0, splitIndex));
|
||||
const server = normalizeLowercaseStringOrEmpty(withoutAt.slice(splitIndex + 1));
|
||||
if (!server) {
|
||||
return value.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(value);
|
||||
}
|
||||
return `@${localpart}:${server.toLowerCase()}`;
|
||||
return `@${localpart}:${server}`;
|
||||
}
|
||||
|
||||
export function normalizeMatrixUserId(raw?: string | null): string {
|
||||
@@ -34,7 +35,7 @@ export function normalizeMatrixUserId(raw?: string | null): string {
|
||||
if (!trimmed) {
|
||||
return "";
|
||||
}
|
||||
const lowered = trimmed.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
if (lowered.startsWith("matrix:")) {
|
||||
return normalizeMatrixUser(trimmed.slice("matrix:".length));
|
||||
}
|
||||
@@ -52,7 +53,7 @@ function normalizeMatrixAllowListEntry(raw: string): string {
|
||||
if (trimmed === "*") {
|
||||
return trimmed;
|
||||
}
|
||||
const lowered = trimmed.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
if (lowered.startsWith("matrix:")) {
|
||||
return `matrix:${normalizeMatrixUser(trimmed.slice("matrix:".length))}`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { getMatrixRuntime } from "../../runtime.js";
|
||||
import type { RoomMessageEventContent } from "./types.js";
|
||||
|
||||
@@ -26,7 +27,7 @@ function decodeNumericHtmlEntity(match: string, rawValue: string, radix: 10 | 16
|
||||
|
||||
function decodeHtmlEntities(value: string): string {
|
||||
return value.replace(/&(#x?[0-9a-f]+|\w+);/gi, (match, entity: string) => {
|
||||
const normalized = entity.toLowerCase();
|
||||
const normalized = normalizeLowercaseStringOrEmpty(entity);
|
||||
if (normalized.startsWith("#x")) {
|
||||
return decodeNumericHtmlEntity(match, normalized.slice(2), 16);
|
||||
}
|
||||
@@ -38,12 +39,11 @@ function decodeHtmlEntities(value: string): string {
|
||||
}
|
||||
|
||||
function normalizeVisibleMentionText(value: string): string {
|
||||
return decodeHtmlEntities(
|
||||
value.replace(/<[^>]+>/g, " ").replace(/[\u200b-\u200f\u202a-\u202e\u2060-\u206f]/g, ""),
|
||||
)
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(
|
||||
decodeHtmlEntities(
|
||||
value.replace(/<[^>]+>/g, " ").replace(/[\u200b-\u200f\u202a-\u202e\u2060-\u206f]/g, ""),
|
||||
).replace(/\s+/g, " "),
|
||||
);
|
||||
}
|
||||
|
||||
function extractVisibleMentionText(value?: string): string {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { getMatrixRuntime } from "../../runtime.js";
|
||||
import type { MatrixClient } from "../sdk.js";
|
||||
import { chunkMatrixText, sendMessageMatrix } from "../send.js";
|
||||
@@ -15,7 +16,7 @@ function shouldSuppressReasoningReplyText(text?: string): boolean {
|
||||
if (!trimmedStart) {
|
||||
return false;
|
||||
}
|
||||
if (trimmedStart.toLowerCase().startsWith("reasoning:")) {
|
||||
if (normalizeLowercaseStringOrEmpty(trimmedStart).startsWith("reasoning:")) {
|
||||
return true;
|
||||
}
|
||||
THINKING_TAG_RE.lastIndex = 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ function resolveMatrixDmSessionKey(params: {
|
||||
kind: "channel",
|
||||
id: params.roomId,
|
||||
},
|
||||
}).toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
function shouldApplyMatrixPerRoomDmSessionScope(params: {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { MatrixClient } from "./sdk.js";
|
||||
|
||||
export const MATRIX_PROFILE_AVATAR_MAX_BYTES = 10 * 1024 * 1024;
|
||||
@@ -24,11 +27,11 @@ export type MatrixProfileSyncResult = {
|
||||
};
|
||||
|
||||
export function isMatrixMxcUri(value: string): boolean {
|
||||
return normalizeOptionalString(value)?.toLowerCase().startsWith("mxc://") ?? false;
|
||||
return normalizeLowercaseStringOrEmpty(normalizeOptionalString(value)).startsWith("mxc://");
|
||||
}
|
||||
|
||||
export function isMatrixHttpAvatarUri(value: string): boolean {
|
||||
const normalized = normalizeOptionalString(value)?.toLowerCase() ?? "";
|
||||
const normalized = normalizeLowercaseStringOrEmpty(normalizeOptionalString(value));
|
||||
return normalized.startsWith("https://") || normalized.startsWith("http://");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalStringifiedId,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import { inspectMatrixDirectRooms, persistMatrixDirectRoomMapping } from "../direct-management.js";
|
||||
import { isStrictDirectRoom } from "../direct-room.js";
|
||||
import type { MatrixClient } from "../sdk.js";
|
||||
@@ -83,7 +86,7 @@ async function resolveDirectRoomId(client: MatrixClient, userId: string): Promis
|
||||
|
||||
export async function resolveMatrixRoomId(client: MatrixClient, raw: string): Promise<string> {
|
||||
const target = normalizeMatrixResolvableTarget(normalizeTarget(raw));
|
||||
const lowered = target.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(target);
|
||||
if (lowered.startsWith("user:")) {
|
||||
return await resolveDirectRoomId(client, target.slice("user:".length));
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
type MatrixTarget = { kind: "room"; id: string } | { kind: "user"; id: string };
|
||||
const MATRIX_PREFIX = "matrix:";
|
||||
const ROOM_PREFIX = "room:";
|
||||
@@ -7,7 +9,7 @@ const USER_PREFIX = "user:";
|
||||
function stripKnownPrefixes(raw: string, prefixes: readonly string[]): string {
|
||||
let normalized = raw.trim();
|
||||
while (normalized) {
|
||||
const lowered = normalized.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(normalized);
|
||||
const matched = prefixes.find((prefix) => lowered.startsWith(prefix));
|
||||
if (!matched) {
|
||||
return normalized;
|
||||
@@ -22,7 +24,7 @@ export function resolveMatrixTargetIdentity(raw: string): MatrixTarget | null {
|
||||
if (!normalized) {
|
||||
return null;
|
||||
}
|
||||
const lowered = normalized.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(normalized);
|
||||
if (lowered.startsWith(USER_PREFIX)) {
|
||||
const id = normalized.slice(USER_PREFIX.length).trim();
|
||||
return id ? { kind: "user", id } : null;
|
||||
@@ -73,7 +75,7 @@ export function normalizeMatrixDirectoryGroupId(raw: string): string | undefined
|
||||
if (!normalized || normalized === "*") {
|
||||
return undefined;
|
||||
}
|
||||
const lowered = normalized.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(normalized);
|
||||
if (lowered.startsWith(ROOM_PREFIX) || lowered.startsWith(CHANNEL_PREFIX)) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
type ChannelSetupWizardAdapter,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js";
|
||||
import { listMatrixDirectoryGroupsLive } from "./directory-live.js";
|
||||
import {
|
||||
@@ -360,7 +361,9 @@ async function configureMatrixAccessPrompts(params: {
|
||||
limit: 10,
|
||||
});
|
||||
const exact = matches.find(
|
||||
(match) => (match.name ?? "").toLowerCase() === trimmed.toLowerCase(),
|
||||
(match) =>
|
||||
normalizeLowercaseStringOrEmpty(match.name) ===
|
||||
normalizeLowercaseStringOrEmpty(trimmed),
|
||||
);
|
||||
const best = exact ?? matches[0];
|
||||
if (best?.id) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
export function sanitizeMatrixPathSegment(value: string): string {
|
||||
const cleaned = value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
const cleaned = normalizeLowercaseStringOrEmpty(value)
|
||||
.replace(/[^a-z0-9._-]+/g, "_")
|
||||
.replace(/^_+|_+$/g, "");
|
||||
return cleaned || "unknown";
|
||||
|
||||
@@ -81,10 +81,9 @@ function readRoomId(params: Record<string, unknown>, required = true): string {
|
||||
}
|
||||
|
||||
function toSnakeCaseKey(key: string): string {
|
||||
return key
|
||||
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
||||
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
||||
.toLowerCase();
|
||||
return normalizeOptionalLowercaseString(
|
||||
key.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z0-9])([A-Z])/g, "$1_$2"),
|
||||
)!;
|
||||
}
|
||||
|
||||
function readRawParam(params: Record<string, unknown>, key: string): unknown {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { parseTelegramTarget } from "./targets.js";
|
||||
|
||||
export function resolveTelegramAutoThreadId(params: {
|
||||
@@ -13,7 +14,10 @@ export function resolveTelegramAutoThreadId(params: {
|
||||
return undefined;
|
||||
}
|
||||
const parsedChannel = parseTelegramTarget(context.currentChannelId);
|
||||
if (parsedTo.chatId.toLowerCase() !== parsedChannel.chatId.toLowerCase()) {
|
||||
if (
|
||||
normalizeLowercaseStringOrEmpty(parsedTo.chatId) !==
|
||||
normalizeLowercaseStringOrEmpty(parsedChannel.chatId)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return context.currentThreadTs;
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/reply-history";
|
||||
import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime";
|
||||
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { NormalizedAllowFrom } from "./bot-access.js";
|
||||
import { isSenderAllowed } from "./bot-access.js";
|
||||
import type {
|
||||
@@ -118,7 +119,7 @@ export async function resolveTelegramInboundBody(params: {
|
||||
historyLimit,
|
||||
logger,
|
||||
} = params;
|
||||
const botUsername = primaryCtx.me?.username?.toLowerCase();
|
||||
const botUsername = normalizeOptionalLowercaseString(primaryCtx.me?.username);
|
||||
const mentionRegexes = buildMentionRegexes(cfg, routeAgentId);
|
||||
const messageTextParts = getTelegramTextParts(msg);
|
||||
const allowForCommands = isGroup ? effectiveGroupAllow : effectiveDmAllow;
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import type { ResolvedAgentRoute } from "openclaw/plugin-sdk/routing";
|
||||
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime";
|
||||
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { NormalizedAllowFrom } from "./bot-access.js";
|
||||
import { isSenderAllowed, normalizeAllowFrom } from "./bot-access.js";
|
||||
import type {
|
||||
@@ -241,7 +242,7 @@ export async function buildTelegramInboundContextPayload(params: {
|
||||
topicConfig,
|
||||
});
|
||||
const commandBody = normalizeCommandBody(rawBody, {
|
||||
botUsername: primaryCtx.me?.username?.toLowerCase(),
|
||||
botUsername: normalizeOptionalLowercaseString(primaryCtx.me?.username),
|
||||
});
|
||||
const inboundHistory =
|
||||
isGroup && historyKey && historyLimit > 0
|
||||
|
||||
@@ -29,6 +29,7 @@ import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-sna
|
||||
import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { getChildLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { resolveTelegramAccount } from "./accounts.js";
|
||||
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
||||
import { isSenderAllowed, normalizeDmAllowFromWithStore } from "./bot-access.js";
|
||||
@@ -506,7 +507,7 @@ export const registerTelegramNativeCommands = ({
|
||||
listNativeCommandSpecs().map((command) => normalizeTelegramCommandName(command.name)),
|
||||
);
|
||||
for (const command of skillCommands) {
|
||||
reservedCommands.add(command.name.toLowerCase());
|
||||
reservedCommands.add(normalizeLowercaseStringOrEmpty(command.name));
|
||||
}
|
||||
const customResolution = resolveTelegramCustomCommands({
|
||||
commands: telegramCfg.customCommands,
|
||||
@@ -524,7 +525,7 @@ export const registerTelegramNativeCommands = ({
|
||||
[
|
||||
...nativeCommands.map((command) => normalizeTelegramCommandName(command.name)),
|
||||
...customCommands.map((command) => command.command),
|
||||
].map((command) => command.toLowerCase()),
|
||||
].map((command) => normalizeLowercaseStringOrEmpty(command)),
|
||||
);
|
||||
const pluginCatalog = buildPluginTelegramMenuCommands({
|
||||
specs: pluginCommandSpecs,
|
||||
|
||||
@@ -20,7 +20,10 @@ import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtim
|
||||
import { getChildLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import { resolveTelegramAccount } from "./accounts.js";
|
||||
import { defaultTelegramBotDeps, type TelegramBotDeps } from "./bot-deps.js";
|
||||
import { registerTelegramHandlers } from "./bot-handlers.js";
|
||||
@@ -129,7 +132,7 @@ function extractTelegramApiMethod(input: TelegramFetchInput): string | null {
|
||||
const pathname = new URL(url).pathname;
|
||||
const segments = pathname.split("/").filter(Boolean);
|
||||
const method = segments.length > 0 ? (segments.at(-1) ?? null) : null;
|
||||
return method?.toLowerCase() ?? null;
|
||||
return normalizeOptionalLowercaseString(method) ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Chat, Message, MessageOrigin, User } from "@grammyjs/types";
|
||||
import type { NormalizedLocation } from "openclaw/plugin-sdk/channel-inbound";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
type TelegramMediaMessage = Pick<
|
||||
Message,
|
||||
@@ -123,8 +126,8 @@ function hasStandaloneTelegramMention(text: string, mention: string): boolean {
|
||||
|
||||
export function hasBotMention(msg: Message, botUsername: string) {
|
||||
const { text, entities } = getTelegramTextParts(msg);
|
||||
const mention = `@${botUsername}`.toLowerCase();
|
||||
if (hasStandaloneTelegramMention(text.toLowerCase(), mention)) {
|
||||
const mention = normalizeLowercaseStringOrEmpty(`@${botUsername}`);
|
||||
if (hasStandaloneTelegramMention(normalizeLowercaseStringOrEmpty(text), mention)) {
|
||||
return true;
|
||||
}
|
||||
for (const ent of entities) {
|
||||
@@ -132,7 +135,7 @@ export function hasBotMention(msg: Message, botUsername: string) {
|
||||
continue;
|
||||
}
|
||||
const slice = text.slice(ent.offset, ent.offset + ent.length);
|
||||
if (slice.toLowerCase() === mention) {
|
||||
if (normalizeLowercaseStringOrEmpty(slice) === mention) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
sanitizeAgentId,
|
||||
} from "openclaw/plugin-sdk/routing";
|
||||
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
buildTelegramGroupPeerId,
|
||||
buildTelegramParentPeer,
|
||||
@@ -64,32 +65,29 @@ export function resolveTelegramConversationRoute(params: {
|
||||
// Preserve the configured topic agent ID so topic-bound sessions stay stable
|
||||
// even when that agent is not present in the current config snapshot.
|
||||
const topicAgentId = sanitizeAgentId(rawTopicAgentId);
|
||||
route = {
|
||||
...route,
|
||||
agentId: topicAgentId,
|
||||
sessionKey: buildAgentSessionKey({
|
||||
const sessionKey = normalizeLowercaseStringOrEmpty(
|
||||
buildAgentSessionKey({
|
||||
agentId: topicAgentId,
|
||||
channel: "telegram",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: params.isGroup ? "group" : "direct", id: peerId },
|
||||
dmScope: params.cfg.session?.dmScope,
|
||||
identityLinks: params.cfg.session?.identityLinks,
|
||||
}).toLowerCase(),
|
||||
mainSessionKey: buildAgentMainSessionKey({
|
||||
}),
|
||||
);
|
||||
const mainSessionKey = normalizeLowercaseStringOrEmpty(
|
||||
buildAgentMainSessionKey({
|
||||
agentId: topicAgentId,
|
||||
}).toLowerCase(),
|
||||
}),
|
||||
);
|
||||
route = {
|
||||
...route,
|
||||
agentId: topicAgentId,
|
||||
sessionKey,
|
||||
mainSessionKey,
|
||||
lastRoutePolicy: deriveLastRoutePolicy({
|
||||
sessionKey: buildAgentSessionKey({
|
||||
agentId: topicAgentId,
|
||||
channel: "telegram",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: params.isGroup ? "group" : "direct", id: peerId },
|
||||
dmScope: params.cfg.session?.dmScope,
|
||||
identityLinks: params.cfg.session?.identityLinks,
|
||||
}).toLowerCase(),
|
||||
mainSessionKey: buildAgentMainSessionKey({
|
||||
agentId: topicAgentId,
|
||||
}).toLowerCase(),
|
||||
sessionKey,
|
||||
mainSessionKey,
|
||||
}),
|
||||
};
|
||||
logVerbose(
|
||||
@@ -170,18 +168,20 @@ export function resolveTelegramConversationBaseSessionKey(params: {
|
||||
if (!isNamedAccountFallback || params.isGroup) {
|
||||
return params.route.sessionKey;
|
||||
}
|
||||
return buildAgentSessionKey({
|
||||
agentId: params.route.agentId,
|
||||
channel: "telegram",
|
||||
accountId: params.route.accountId,
|
||||
peer: {
|
||||
kind: "direct",
|
||||
id: resolveTelegramDirectPeerId({
|
||||
chatId: params.chatId,
|
||||
senderId: params.senderId,
|
||||
}),
|
||||
},
|
||||
dmScope: "per-account-channel-peer",
|
||||
identityLinks: params.cfg.session?.identityLinks,
|
||||
}).toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(
|
||||
buildAgentSessionKey({
|
||||
agentId: params.route.agentId,
|
||||
channel: "telegram",
|
||||
accountId: params.route.accountId,
|
||||
peer: {
|
||||
kind: "direct",
|
||||
id: resolveTelegramDirectPeerId({
|
||||
chatId: params.chatId,
|
||||
senderId: params.senderId,
|
||||
}),
|
||||
},
|
||||
dmScope: "per-account-channel-peer",
|
||||
identityLinks: params.cfg.session?.identityLinks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -402,7 +402,9 @@ function formatErrorCodes(err: unknown): string {
|
||||
function shouldUseTelegramTransportFallback(err: unknown): boolean {
|
||||
const ctx: TelegramTransportFallbackContext = {
|
||||
message:
|
||||
err && typeof err === "object" && "message" in err ? String(err.message).toLowerCase() : "",
|
||||
err && typeof err === "object" && "message" in err
|
||||
? normalizeLowercaseStringOrEmpty(String(err.message))
|
||||
: "",
|
||||
codes: collectErrorCodes(err),
|
||||
};
|
||||
for (const rule of TELEGRAM_TRANSPORT_FALLBACK_RULES) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
FILE_REF_EXTENSIONS_WITH_TLD,
|
||||
isAutoLinkedFileRef,
|
||||
markdownToIR,
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
type MarkdownLinkSpan,
|
||||
type MarkdownIR,
|
||||
renderMarkdownIRChunksWithinLimit,
|
||||
@@ -182,7 +183,7 @@ export function wrapFileReferencesInHtml(html: string): string {
|
||||
const tagStart = match.index;
|
||||
const tagEnd = HTML_TAG_PATTERN.lastIndex;
|
||||
const isClosing = match[1] === "</";
|
||||
const tagName = match[2].toLowerCase();
|
||||
const tagName = normalizeLowercaseStringOrEmpty(match[2]);
|
||||
|
||||
// Process text before this tag
|
||||
const textBefore = deLinkified.slice(lastIndex, tagStart);
|
||||
@@ -393,7 +394,7 @@ export function splitTelegramHtmlChunks(html: string, limit: number): string[] {
|
||||
|
||||
const rawTag = match[0];
|
||||
const isClosing = match[1] === "</";
|
||||
const tagName = match[2].toLowerCase();
|
||||
const tagName = normalizeLowercaseStringOrEmpty(match[2]);
|
||||
const isSelfClosing =
|
||||
!isClosing &&
|
||||
(TELEGRAM_SELF_CLOSING_HTML_TAGS.has(tagName) || rawTag.trimEnd().endsWith("/>"));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import type { TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
type TelegramGroups = Record<string, TelegramGroupConfig>;
|
||||
|
||||
@@ -29,7 +30,7 @@ function resolveAccountGroups(
|
||||
return { groups: exact.groups };
|
||||
}
|
||||
const matchKey = Object.keys(accounts).find(
|
||||
(key) => key.toLowerCase() === normalized.toLowerCase(),
|
||||
(key) => normalizeLowercaseStringOrEmpty(key) === normalizeLowercaseStringOrEmpty(normalized),
|
||||
);
|
||||
return { groups: matchKey ? accounts[matchKey]?.groups : undefined };
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ function normalizeTelegramNetworkMethod(method?: string | null): string | null {
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
return trimmed.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(trimmed);
|
||||
}
|
||||
|
||||
export function tagTelegramNetworkError(err: unknown, origin: TelegramNetworkErrorOrigin): void {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { normalizeTelegramLookupTarget, parseTelegramTarget } from "./targets.js";
|
||||
|
||||
const TELEGRAM_PREFIX_RE = /^(telegram|tg):/i;
|
||||
@@ -36,7 +37,7 @@ export function normalizeTelegramMessagingTarget(raw: string): string | undefine
|
||||
if (!normalizedBody) {
|
||||
return undefined;
|
||||
}
|
||||
return `telegram:${normalizedBody}`.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(`telegram:${normalizedBody}`);
|
||||
}
|
||||
|
||||
export function looksLikeTelegramTargetId(raw: string): boolean {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
sleepWithAbort,
|
||||
} from "openclaw/plugin-sdk/runtime-env";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
||||
import { createTelegramBot } from "./bot.js";
|
||||
import { type TelegramTransport } from "./fetch.js";
|
||||
@@ -450,7 +451,7 @@ const isGetUpdatesConflict = (err: unknown) => {
|
||||
}
|
||||
const haystack = [typed.method, typed.description, typed.message]
|
||||
.filter((value): value is string => typeof value === "string")
|
||||
.join(" ")
|
||||
.toLowerCase();
|
||||
return haystack.includes("getupdates");
|
||||
.join(" ");
|
||||
const normalizedHaystack = normalizeLowercaseStringOrEmpty(haystack);
|
||||
return normalizedHaystack.includes("getupdates");
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { formatReasoningMessage } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
|
||||
import { findCodeRegions, isInsideCode } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
stripReasoningTagsFromText,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
const REASONING_MESSAGE_PREFIX = "Reasoning:\n";
|
||||
const REASONING_TAG_PREFIXES = [
|
||||
@@ -44,7 +47,7 @@ function extractThinkingFromTaggedStreamOutsideCode(text: string): string {
|
||||
}
|
||||
|
||||
function isPartialReasoningTagPrefix(text: string): boolean {
|
||||
const trimmed = text.trimStart().toLowerCase();
|
||||
const trimmed = normalizeLowercaseStringOrEmpty(text.trimStart());
|
||||
if (!trimmed.startsWith("<")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
sleepWithAbort,
|
||||
type BackoffPolicy,
|
||||
} from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
export type TelegramSendChatActionLogger = (message: string) => void;
|
||||
|
||||
@@ -60,7 +61,9 @@ function is401Error(error: unknown): boolean {
|
||||
return false;
|
||||
}
|
||||
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
return message.includes("401") || message.toLowerCase().includes("unauthorized");
|
||||
return (
|
||||
message.includes("401") || normalizeLowercaseStringOrEmpty(message).includes("unauthorized")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/media-runtime";
|
||||
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { STATE_DIR } from "openclaw/plugin-sdk/state-paths";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { getTelegramRuntime } from "./runtime.js";
|
||||
|
||||
const CACHE_FILE = path.join(STATE_DIR, "telegram", "sticker-cache.json");
|
||||
@@ -75,12 +76,12 @@ export function cacheSticker(sticker: CachedSticker): void {
|
||||
*/
|
||||
export function searchStickers(query: string, limit = 10): CachedSticker[] {
|
||||
const cache = loadCache();
|
||||
const queryLower = query.toLowerCase();
|
||||
const queryLower = normalizeLowercaseStringOrEmpty(query);
|
||||
const results: Array<{ sticker: CachedSticker; score: number }> = [];
|
||||
|
||||
for (const sticker of Object.values(cache.stickers)) {
|
||||
let score = 0;
|
||||
const descLower = sticker.description.toLowerCase();
|
||||
const descLower = normalizeLowercaseStringOrEmpty(sticker.description);
|
||||
|
||||
// Exact substring match in description
|
||||
if (descLower.includes(queryLower)) {
|
||||
@@ -102,7 +103,7 @@ export function searchStickers(query: string, limit = 10): CachedSticker[] {
|
||||
}
|
||||
|
||||
// Set name match
|
||||
if (sticker.setName?.toLowerCase().includes(queryLower)) {
|
||||
if (normalizeLowercaseStringOrEmpty(sticker.setName).includes(queryLower)) {
|
||||
score += 3;
|
||||
}
|
||||
|
||||
@@ -193,7 +194,8 @@ export async function describeStickerImage(params: DescribeStickerParams): Promi
|
||||
const selectCatalogModel = (provider: string) => {
|
||||
const entries = catalog.filter(
|
||||
(entry) =>
|
||||
entry.provider.toLowerCase() === provider.toLowerCase() && modelSupportsVision(entry),
|
||||
normalizeLowercaseStringOrEmpty(entry.provider) ===
|
||||
normalizeLowercaseStringOrEmpty(provider) && modelSupportsVision(entry),
|
||||
);
|
||||
if (entries.length === 0) {
|
||||
return undefined;
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
saveCronStore,
|
||||
} from "openclaw/plugin-sdk/config-runtime";
|
||||
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import {
|
||||
normalizeTelegramChatId,
|
||||
normalizeTelegramLookupTarget,
|
||||
@@ -30,7 +31,7 @@ function normalizeTelegramLookupTargetForMatch(raw: string): string | undefined
|
||||
if (!normalized) {
|
||||
return undefined;
|
||||
}
|
||||
return normalized.startsWith("@") ? normalized.toLowerCase() : normalized;
|
||||
return normalized.startsWith("@") ? normalizeLowercaseStringOrEmpty(normalized) : normalized;
|
||||
}
|
||||
|
||||
function normalizeTelegramTargetForMatch(raw: string): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user