From 434d56a948a7339448cbee966f943e59abf33865 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 7 Apr 2026 10:18:06 +0100 Subject: [PATCH] refactor: dedupe lowercase helper readers --- src/acp/runtime/registry.ts | 10 ++++---- src/auto-reply/reply/channel-context.ts | 7 ++++-- src/auto-reply/reply/commands-compact.ts | 7 ++++-- src/auto-reply/reply/plugins-commands.ts | 7 ++++-- src/channels/conversation-binding-context.ts | 7 ++++-- src/channels/ids.ts | 8 +++---- src/channels/model-overrides.ts | 24 +++++++++++--------- src/channels/registry.ts | 15 +++++++----- src/channels/status-reactions.ts | 4 ++-- src/config/sessions/metadata.ts | 7 ++++-- src/gateway/exec-approval-ios-push.ts | 4 ++-- src/gateway/protocol/client-info.ts | 6 ++--- src/gateway/server-mobile-nodes.ts | 4 ++-- src/infra/exec-approvals.ts | 14 ++++++++---- src/plugins/provider-wizard.ts | 9 +++++--- src/sessions/send-policy.ts | 8 +++---- src/shared/node-match.ts | 6 ++--- src/shared/string-normalization.ts | 6 ++--- src/utils/transcript-tools.ts | 7 ++++-- 19 files changed, 95 insertions(+), 65 deletions(-) diff --git a/src/acp/runtime/registry.ts b/src/acp/runtime/registry.ts index 6f93099fb05..5521aea79aa 100644 --- a/src/acp/runtime/registry.ts +++ b/src/acp/runtime/registry.ts @@ -1,5 +1,5 @@ import { resolveGlobalSingleton } from "../../shared/global-singleton.js"; -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js"; import { AcpRuntimeError } from "./errors.js"; import type { AcpRuntime } from "./types.js"; @@ -38,7 +38,7 @@ function isBackendHealthy(backend: AcpRuntimeBackend): boolean { } export function registerAcpRuntimeBackend(backend: AcpRuntimeBackend): void { - const id = normalizeOptionalString(backend.id)?.toLowerCase() || ""; + const id = normalizeOptionalLowercaseString(backend.id) || ""; if (!id) { throw new Error("ACP runtime backend id is required"); } @@ -52,7 +52,7 @@ export function registerAcpRuntimeBackend(backend: AcpRuntimeBackend): void { } export function unregisterAcpRuntimeBackend(id: string): void { - const normalized = normalizeOptionalString(id)?.toLowerCase() || ""; + const normalized = normalizeOptionalLowercaseString(id) || ""; if (!normalized) { return; } @@ -60,7 +60,7 @@ export function unregisterAcpRuntimeBackend(id: string): void { } export function getAcpRuntimeBackend(id?: string): AcpRuntimeBackend | null { - const normalized = normalizeOptionalString(id)?.toLowerCase() || ""; + const normalized = normalizeOptionalLowercaseString(id) || ""; if (normalized) { return ACP_BACKENDS_BY_ID.get(normalized) ?? null; } @@ -76,7 +76,7 @@ export function getAcpRuntimeBackend(id?: string): AcpRuntimeBackend | null { } export function requireAcpRuntimeBackend(id?: string): AcpRuntimeBackend { - const normalized = normalizeOptionalString(id)?.toLowerCase() || ""; + const normalized = normalizeOptionalLowercaseString(id) || ""; const backend = getAcpRuntimeBackend(normalized || undefined); if (!backend) { throw new AcpRuntimeError( diff --git a/src/auto-reply/reply/channel-context.ts b/src/auto-reply/reply/channel-context.ts index 81e6409c032..d0f5a88d00e 100644 --- a/src/auto-reply/reply/channel-context.ts +++ b/src/auto-reply/reply/channel-context.ts @@ -1,6 +1,9 @@ import type { OpenClawConfig } from "../../config/config.js"; import { getActivePluginChannelRegistry } from "../../plugins/runtime.js"; -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../../shared/string-coerce.js"; type CommandSurfaceParams = { ctx: { @@ -33,7 +36,7 @@ export function resolveCommandSurfaceChannel(params: CommandSurfaceParams): stri params.command.channel ?? params.ctx.Surface ?? params.ctx.Provider; - return normalizeOptionalString(channel)?.toLowerCase() ?? ""; + return normalizeOptionalLowercaseString(channel) ?? ""; } export function resolveChannelAccountId(params: ChannelAccountParams): string { diff --git a/src/auto-reply/reply/commands-compact.ts b/src/auto-reply/reply/commands-compact.ts index ef43e6a97ee..0010c2db75d 100644 --- a/src/auto-reply/reply/commands-compact.ts +++ b/src/auto-reply/reply/commands-compact.ts @@ -1,6 +1,9 @@ import type { OpenClawConfig } from "../../config/config.js"; import { logVerbose } from "../../globals.js"; -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../../shared/string-coerce.js"; import type { CommandHandler } from "./commands-types.js"; import { stripMentions, stripStructuralPrefixes } from "./mentions.js"; @@ -32,7 +35,7 @@ function extractCompactInstructions(params: { } function isCompactionSkipReason(reason?: string): boolean { - const text = normalizeOptionalString(reason)?.toLowerCase() ?? ""; + const text = normalizeOptionalLowercaseString(reason) ?? ""; return ( text.includes("nothing to compact") || text.includes("below threshold") || diff --git a/src/auto-reply/reply/plugins-commands.ts b/src/auto-reply/reply/plugins-commands.ts index 36b41ce0bf6..8fc050c7a75 100644 --- a/src/auto-reply/reply/plugins-commands.ts +++ b/src/auto-reply/reply/plugins-commands.ts @@ -1,4 +1,7 @@ -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../../shared/string-coerce.js"; export type PluginsCommand = | { action: "list" } @@ -20,7 +23,7 @@ export function parsePluginsCommand(raw: string): PluginsCommand | null { } const [rawAction, ...rest] = tail.split(/\s+/); - const action = normalizeOptionalString(rawAction)?.toLowerCase(); + const action = normalizeOptionalLowercaseString(rawAction); const name = rest.join(" ").trim(); if (action === "list") { diff --git a/src/channels/conversation-binding-context.ts b/src/channels/conversation-binding-context.ts index addf62aca65..a7289f78ba6 100644 --- a/src/channels/conversation-binding-context.ts +++ b/src/channels/conversation-binding-context.ts @@ -1,7 +1,10 @@ import type { OpenClawConfig } from "../config/config.js"; import { resolveConversationIdFromTargets } from "../infra/outbound/conversation-id.js"; import { getActivePluginChannelRegistry } from "../plugins/runtime.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../shared/string-coerce.js"; import { parseExplicitTargetForChannel } from "./plugins/target-parsing.js"; import type { ChannelPlugin } from "./plugins/types.js"; import { normalizeAnyChannelId, normalizeChannelId } from "./registry.js"; @@ -128,7 +131,7 @@ export function resolveConversationBindingContext( const channel = normalizeAnyChannelId(params.channel) ?? normalizeChannelId(params.channel) ?? - normalizeOptionalString(params.channel)?.toLowerCase(); + normalizeOptionalLowercaseString(params.channel); if (!channel) { return null; } diff --git a/src/channels/ids.ts b/src/channels/ids.ts index 3c3af4d7fbb..11c3f5a6dd1 100644 --- a/src/channels/ids.ts +++ b/src/channels/ids.ts @@ -1,5 +1,5 @@ import { listChannelCatalogEntries } from "../plugins/channel-catalog-registry.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; export type ChatChannelId = string; @@ -12,12 +12,12 @@ type BundledChatChannelEntry = { function listBundledChatChannelEntries(): BundledChatChannelEntry[] { return listChannelCatalogEntries({ origin: "bundled" }) .flatMap(({ channel }) => { - const id = normalizeOptionalString(channel.id)?.toLowerCase(); + const id = normalizeOptionalLowercaseString(channel.id); if (!id) { return []; } const aliases = (channel.aliases ?? []) - .map((alias) => normalizeOptionalString(alias)?.toLowerCase()) + .map((alias) => normalizeOptionalLowercaseString(alias)) .filter((alias): alias is string => Boolean(alias)); return [ { @@ -55,7 +55,7 @@ export function listChatChannelAliases(): string[] { } export function normalizeChatChannelId(raw?: string | null): ChatChannelId | null { - const normalized = normalizeOptionalString(raw)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(raw); if (!normalized) { return null; } diff --git a/src/channels/model-overrides.ts b/src/channels/model-overrides.ts index f0411b9dcfd..ccb560b1b17 100644 --- a/src/channels/model-overrides.ts +++ b/src/channels/model-overrides.ts @@ -1,5 +1,8 @@ import type { OpenClawConfig } from "../config/config.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../shared/string-coerce.js"; import { normalizeMessageChannel } from "../utils/message-channel.js"; import { buildChannelKeyCandidates, @@ -38,13 +41,13 @@ function resolveProviderEntry( channel: string, ): Record | undefined { const normalized = - normalizeMessageChannel(channel) ?? normalizeOptionalString(channel)?.toLowerCase() ?? ""; + normalizeMessageChannel(channel) ?? normalizeOptionalLowercaseString(channel) ?? ""; return ( modelByChannel?.[normalized] ?? modelByChannel?.[ Object.keys(modelByChannel ?? {}).find((key) => { const normalizedKey = - normalizeMessageChannel(key) ?? normalizeOptionalString(key)?.toLowerCase() ?? ""; + normalizeMessageChannel(key) ?? normalizeOptionalLowercaseString(key) ?? ""; return normalizedKey === normalized; }) ?? "" ] @@ -59,7 +62,7 @@ function buildChannelCandidates( ): { keys: string[]; parentKeys: string[] } { const normalizedChannel = normalizeMessageChannel(params.channel ?? "") ?? - normalizeOptionalString(params.channel)?.toLowerCase(); + normalizeOptionalLowercaseString(params.channel); const groupId = normalizeOptionalString(params.groupId); const sessionConversation = resolveSessionConversationRef(params.parentSessionKey); const feishuParentOverrideFallbacks = @@ -119,23 +122,23 @@ function buildFeishuParentOverrideCandidates(rawId: string | undefined): string[ } const topicSenderMatch = value.match(/^(.+):topic:([^:]+):sender:([^:]+)$/i); if (topicSenderMatch) { - const chatId = normalizeOptionalString(topicSenderMatch[1])?.toLowerCase(); - const topicId = normalizeOptionalString(topicSenderMatch[2])?.toLowerCase(); + const chatId = normalizeOptionalLowercaseString(topicSenderMatch[1]); + const topicId = normalizeOptionalLowercaseString(topicSenderMatch[2]); return [`${chatId}:topic:${topicId}`, chatId].filter((entry): entry is string => Boolean(entry), ); } const topicMatch = value.match(/^(.+):topic:([^:]+)$/i); if (topicMatch) { - const chatId = normalizeOptionalString(topicMatch[1])?.toLowerCase(); - const topicId = normalizeOptionalString(topicMatch[2])?.toLowerCase(); + const chatId = normalizeOptionalLowercaseString(topicMatch[1]); + const topicId = normalizeOptionalLowercaseString(topicMatch[2]); return [`${chatId}:topic:${topicId}`, chatId].filter((entry): entry is string => Boolean(entry), ); } const senderMatch = value.match(/^(.+):sender:([^:]+)$/i); if (senderMatch) { - const chatId = normalizeOptionalString(senderMatch[1])?.toLowerCase(); + const chatId = normalizeOptionalLowercaseString(senderMatch[1]); return chatId ? [chatId] : []; } return []; @@ -180,8 +183,7 @@ export function resolveChannelModelOverride( } return { - channel: - normalizeMessageChannel(channel) ?? normalizeOptionalString(channel)?.toLowerCase() ?? "", + channel: normalizeMessageChannel(channel) ?? normalizeOptionalLowercaseString(channel) ?? "", model, matchKey: match.matchKey, matchSource: match.matchSource, diff --git a/src/channels/registry.ts b/src/channels/registry.ts index 7ee9b557dcb..ef30b238bd1 100644 --- a/src/channels/registry.ts +++ b/src/channels/registry.ts @@ -1,5 +1,8 @@ import { getActivePluginChannelRegistry, getActivePluginRegistry } from "../plugins/runtime.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../shared/string-coerce.js"; import { getChatChannelMeta, listChatChannels, type ChatChannelMeta } from "./chat-meta.js"; import { CHANNEL_IDS, @@ -32,12 +35,12 @@ function findRegisteredChannelPluginEntry( normalizedKey: string, ): RegisteredChannelPluginEntry | undefined { return listRegisteredChannelPluginEntries().find((entry) => { - const id = normalizeOptionalString(String(entry.plugin.id ?? ""))?.toLowerCase() ?? ""; + const id = normalizeOptionalLowercaseString(String(entry.plugin.id ?? "")) ?? ""; if (id && id === normalizedKey) { return true; } return (entry.plugin.meta?.aliases ?? []).some( - (alias) => normalizeOptionalString(alias)?.toLowerCase() === normalizedKey, + (alias) => normalizeOptionalLowercaseString(alias) === normalizedKey, ); }); } @@ -45,12 +48,12 @@ function findRegisteredChannelPluginEntry( function findRegisteredChannelPluginEntryById( id: string, ): RegisteredChannelPluginEntry | undefined { - const normalizedId = normalizeOptionalString(id)?.toLowerCase(); + const normalizedId = normalizeOptionalLowercaseString(id); if (!normalizedId) { return undefined; } return listRegisteredChannelPluginEntries().find( - (entry) => normalizeOptionalString(entry.plugin.id)?.toLowerCase() === normalizedId, + (entry) => normalizeOptionalLowercaseString(entry.plugin.id) === normalizedId, ); } export { @@ -72,7 +75,7 @@ export function normalizeChannelId(raw?: string | null): ChatChannelId | null { // Keep this light: we do not import channel plugins here (those are "heavy" and can pull in // monitors, web login, etc). The plugin registry must be initialized first. export function normalizeAnyChannelId(raw?: string | null): ChannelId | null { - const key = normalizeOptionalString(raw)?.toLowerCase(); + const key = normalizeOptionalLowercaseString(raw); if (!key) { return null; } diff --git a/src/channels/status-reactions.ts b/src/channels/status-reactions.ts index c3203aac4b5..2b553aa366a 100644 --- a/src/channels/status-reactions.ts +++ b/src/channels/status-reactions.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; /** * Channel-agnostic status reaction controller. @@ -104,7 +104,7 @@ export function resolveToolEmoji( toolName: string | undefined, emojis: Required, ): string { - const normalized = normalizeOptionalString(toolName)?.toLowerCase() ?? ""; + const normalized = normalizeOptionalLowercaseString(toolName) ?? ""; if (!normalized) { return emojis.tool; } diff --git a/src/config/sessions/metadata.ts b/src/config/sessions/metadata.ts index e93340fec0b..134e99d5f39 100644 --- a/src/config/sessions/metadata.ts +++ b/src/config/sessions/metadata.ts @@ -2,7 +2,10 @@ import type { MsgContext } from "../../auto-reply/templating.js"; import { normalizeChatType } from "../../channels/chat-type.js"; import { resolveConversationLabel } from "../../channels/conversation-label.js"; import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js"; -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../../shared/string-coerce.js"; import { normalizeMessageChannel } from "../../utils/message-channel.js"; import { buildGroupDisplayName, resolveGroupSessionKey } from "./group.js"; import type { GroupKeyResolution, SessionEntry, SessionOrigin } from "./types.js"; @@ -55,7 +58,7 @@ export function deriveSessionOrigin(ctx: MsgContext): SessionOrigin | undefined ctx.Surface || ctx.Provider; const provider = normalizeMessageChannel(providerRaw); - const surface = normalizeOptionalString(ctx.Surface)?.toLowerCase(); + const surface = normalizeOptionalLowercaseString(ctx.Surface); const chatType = normalizeChatType(ctx.ChatType) ?? undefined; const from = normalizeOptionalString(ctx.From); const to = normalizeOptionalString( diff --git a/src/gateway/exec-approval-ios-push.ts b/src/gateway/exec-approval-ios-push.ts index 75e4251f3c5..8b78b90bc06 100644 --- a/src/gateway/exec-approval-ios-push.ts +++ b/src/gateway/exec-approval-ios-push.ts @@ -20,7 +20,7 @@ import { type ApnsRelayConfig, } from "../infra/push-apns.js"; import { roleScopesAllow } from "../shared/operator-scope-compat.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; const APPROVALS_SCOPE = "operator.approvals"; const OPERATOR_ROLE = "operator"; @@ -48,7 +48,7 @@ type ApprovalDeliveryState = { }; function isIosPlatform(platform: string | undefined): boolean { - const normalized = normalizeOptionalString(platform)?.toLowerCase() ?? ""; + const normalized = normalizeOptionalLowercaseString(platform) ?? ""; return normalized.startsWith("ios") || normalized.startsWith("ipados"); } diff --git a/src/gateway/protocol/client-info.ts b/src/gateway/protocol/client-info.ts index 2829e5dfab2..fe6576c13c4 100644 --- a/src/gateway/protocol/client-info.ts +++ b/src/gateway/protocol/client-info.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js"; export const GATEWAY_CLIENT_IDS = { WEBCHAT_UI: "webchat-ui", @@ -55,7 +55,7 @@ const GATEWAY_CLIENT_ID_SET = new Set(Object.values(GATEWAY_CLI const GATEWAY_CLIENT_MODE_SET = new Set(Object.values(GATEWAY_CLIENT_MODES)); export function normalizeGatewayClientId(raw?: string | null): GatewayClientId | undefined { - const normalized = normalizeOptionalString(raw)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(raw); if (!normalized) { return undefined; } @@ -69,7 +69,7 @@ export function normalizeGatewayClientName(raw?: string | null): GatewayClientNa } export function normalizeGatewayClientMode(raw?: string | null): GatewayClientMode | undefined { - const normalized = normalizeOptionalString(raw)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(raw); if (!normalized) { return undefined; } diff --git a/src/gateway/server-mobile-nodes.ts b/src/gateway/server-mobile-nodes.ts index 38187b1d332..12535fc0176 100644 --- a/src/gateway/server-mobile-nodes.ts +++ b/src/gateway/server-mobile-nodes.ts @@ -1,10 +1,10 @@ -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; import type { NodeRegistry } from "./node-registry.js"; export function hasConnectedMobileNode(registry: NodeRegistry): boolean { const connected = registry.listConnected(); return connected.some((n) => { - const platform = normalizeOptionalString(n.platform)?.toLowerCase() ?? ""; + const platform = normalizeOptionalLowercaseString(n.platform) ?? ""; return ( platform.startsWith("ios") || platform.startsWith("ipados") || platform.startsWith("android") ); diff --git a/src/infra/exec-approvals.ts b/src/infra/exec-approvals.ts index fdfd6a58a69..548cc5b0053 100644 --- a/src/infra/exec-approvals.ts +++ b/src/infra/exec-approvals.ts @@ -2,7 +2,11 @@ import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { DEFAULT_AGENT_ID } from "../routing/session-key.js"; -import { normalizeOptionalString, readStringValue } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, + readStringValue, +} from "../shared/string-coerce.js"; import { resolveAllowAlwaysPatternEntries } from "./exec-approvals-allowlist.js"; import type { ExecCommandSegment } from "./exec-approvals-analysis.js"; import { expandHomePrefix } from "./home-dir.js"; @@ -16,7 +20,7 @@ export type ExecSecurity = "deny" | "allowlist" | "full"; export type ExecAsk = "off" | "on-miss" | "always"; export function normalizeExecHost(value?: string | null): ExecHost | null { - const normalized = normalizeOptionalString(value)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(value); if (normalized === "sandbox" || normalized === "gateway" || normalized === "node") { return normalized; } @@ -24,7 +28,7 @@ export function normalizeExecHost(value?: string | null): ExecHost | null { } export function normalizeExecTarget(value?: string | null): ExecTarget | null { - const normalized = normalizeOptionalString(value)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(value); if (normalized === "auto") { return normalized; } @@ -35,7 +39,7 @@ export function normalizeExecTarget(value?: string | null): ExecTarget | null { const toStringOrUndefined = readStringValue; export function normalizeExecSecurity(value?: string | null): ExecSecurity | null { - const normalized = normalizeOptionalString(value)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(value); if (normalized === "deny" || normalized === "allowlist" || normalized === "full") { return normalized; } @@ -43,7 +47,7 @@ export function normalizeExecSecurity(value?: string | null): ExecSecurity | nul } export function normalizeExecAsk(value?: string | null): ExecAsk | null { - const normalized = normalizeOptionalString(value)?.toLowerCase(); + const normalized = normalizeOptionalLowercaseString(value); if (normalized === "off" || normalized === "on-miss" || normalized === "always") { return normalized; } diff --git a/src/plugins/provider-wizard.ts b/src/plugins/provider-wizard.ts index 550291c177c..beb8b899413 100644 --- a/src/plugins/provider-wizard.ts +++ b/src/plugins/provider-wizard.ts @@ -1,7 +1,10 @@ import { DEFAULT_PROVIDER } from "../agents/defaults.js"; import { normalizeProviderId } from "../agents/model-selection.js"; import type { OpenClawConfig } from "../config/config.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../shared/string-coerce.js"; import type { WizardPrompter } from "../wizard/prompts.js"; import { resolvePluginProviders } from "./providers.runtime.js"; import type { @@ -53,12 +56,12 @@ function resolveMethodById( provider: ProviderPlugin, methodId?: string, ): ProviderAuthMethod | undefined { - const normalizedMethodId = normalizeOptionalString(methodId)?.toLowerCase(); + const normalizedMethodId = normalizeOptionalLowercaseString(methodId); if (!normalizedMethodId) { return provider.auth[0]; } return provider.auth.find( - (method) => normalizeOptionalString(method.id)?.toLowerCase() === normalizedMethodId, + (method) => normalizeOptionalLowercaseString(method.id) === normalizedMethodId, ); } diff --git a/src/sessions/send-policy.ts b/src/sessions/send-policy.ts index 2c16a3b50c6..0d1ad6e76ae 100644 --- a/src/sessions/send-policy.ts +++ b/src/sessions/send-policy.ts @@ -1,12 +1,12 @@ import { normalizeChatType } from "../channels/chat-type.js"; import type { OpenClawConfig } from "../config/config.js"; import type { SessionChatType, SessionEntry } from "../config/sessions.js"; -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; export type SessionSendPolicyDecision = "allow" | "deny"; export function normalizeSendPolicy(raw?: string | null): SessionSendPolicyDecision | undefined { - const value = normalizeOptionalString(raw)?.toLowerCase(); + const value = normalizeOptionalLowercaseString(raw); if (value === "allow") { return "allow"; } @@ -17,7 +17,7 @@ export function normalizeSendPolicy(raw?: string | null): SessionSendPolicyDecis } function normalizeMatchValue(raw?: string | null) { - const value = normalizeOptionalString(raw)?.toLowerCase(); + const value = normalizeOptionalLowercaseString(raw); return value ? value : undefined; } @@ -46,7 +46,7 @@ function deriveChannelFromKey(key?: string) { } function deriveChatTypeFromKey(key?: string): SessionChatType | undefined { - const normalizedKey = normalizeOptionalString(stripAgentSessionKeyPrefix(key))?.toLowerCase(); + const normalizedKey = normalizeOptionalLowercaseString(stripAgentSessionKeyPrefix(key)); if (!normalizedKey) { return undefined; } diff --git a/src/shared/node-match.ts b/src/shared/node-match.ts index e5acf07d6e5..2ce3ae30cde 100644 --- a/src/shared/node-match.ts +++ b/src/shared/node-match.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "./string-coerce.js"; +import { normalizeOptionalLowercaseString, normalizeOptionalString } from "./string-coerce.js"; export type NodeMatchCandidate = { nodeId: string; @@ -40,12 +40,12 @@ function formatNodeCandidateLabel(node: NodeMatchCandidate): string { } function isCurrentOpenClawClient(clientId: string | undefined): boolean { - const normalized = normalizeOptionalString(clientId)?.toLowerCase() ?? ""; + const normalized = normalizeOptionalLowercaseString(clientId) ?? ""; return normalized.startsWith("openclaw-"); } function isLegacyClawdbotClient(clientId: string | undefined): boolean { - const normalized = normalizeOptionalString(clientId)?.toLowerCase() ?? ""; + const normalized = normalizeOptionalLowercaseString(clientId) ?? ""; return normalized.startsWith("clawdbot-") || normalized.startsWith("moldbot-"); } diff --git a/src/shared/string-normalization.ts b/src/shared/string-normalization.ts index 2581672105e..2e0985daa9b 100644 --- a/src/shared/string-normalization.ts +++ b/src/shared/string-normalization.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "./string-coerce.js"; +import { normalizeOptionalLowercaseString, normalizeOptionalString } from "./string-coerce.js"; export function normalizeStringEntries(list?: ReadonlyArray) { return (list ?? []).map((entry) => String(entry).trim()).filter(Boolean); @@ -52,7 +52,7 @@ export function normalizeCsvOrLooseStringList(value: unknown): string[] { } export function normalizeHyphenSlug(raw?: string | null) { - const trimmed = normalizeOptionalString(raw)?.toLowerCase() ?? ""; + const trimmed = normalizeOptionalLowercaseString(raw) ?? ""; if (!trimmed) { return ""; } @@ -62,7 +62,7 @@ export function normalizeHyphenSlug(raw?: string | null) { } export function normalizeAtHashSlug(raw?: string | null) { - const trimmed = normalizeOptionalString(raw)?.toLowerCase() ?? ""; + const trimmed = normalizeOptionalLowercaseString(raw) ?? ""; if (!trimmed) { return ""; } diff --git a/src/utils/transcript-tools.ts b/src/utils/transcript-tools.ts index 32fbe1d195c..85604102cd0 100644 --- a/src/utils/transcript-tools.ts +++ b/src/utils/transcript-tools.ts @@ -1,4 +1,7 @@ -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "../shared/string-coerce.js"; type ToolResultCounts = { total: number; @@ -9,7 +12,7 @@ const TOOL_CALL_TYPES = new Set(["tool_use", "toolcall", "tool_call"]); const TOOL_RESULT_TYPES = new Set(["tool_result", "tool_result_error"]); const normalizeType = (value: unknown): string => { - return typeof value === "string" ? (normalizeOptionalString(value)?.toLowerCase() ?? "") : ""; + return typeof value === "string" ? (normalizeOptionalLowercaseString(value) ?? "") : ""; }; export const extractToolCallNames = (message: Record): string[] => {