From fbdb20ffd3005f91c227def385a06324d12cad11 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 7 Apr 2026 10:48:12 +0100 Subject: [PATCH] refactor: dedupe reply lowercase helpers --- src/agents/mcp-transport-config.ts | 3 ++- src/agents/pi-embedded-runner/compact-reasons.ts | 6 ++++-- src/agents/tools/sessions-access.ts | 3 ++- src/auto-reply/command-auth.ts | 3 ++- src/auto-reply/reply/commands-context.ts | 5 +++-- src/auto-reply/reply/session-delivery.ts | 11 +++++++---- src/auto-reply/tool-meta.ts | 3 ++- 7 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/agents/mcp-transport-config.ts b/src/agents/mcp-transport-config.ts index 486dafa3ff3..7bb68b80d6b 100644 --- a/src/agents/mcp-transport-config.ts +++ b/src/agents/mcp-transport-config.ts @@ -1,4 +1,5 @@ import { logWarn } from "../logger.js"; +import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; import { describeHttpMcpServerLaunchConfig, resolveHttpMcpServerLaunchConfig, @@ -58,7 +59,7 @@ function getRequestedTransport(rawServer: unknown): string { ) { return ""; } - return ((rawServer as { transport?: string }).transport ?? "").trim().toLowerCase(); + return normalizeLowercaseStringOrEmpty((rawServer as { transport?: string }).transport); } function resolveHttpTransportConfig( diff --git a/src/agents/pi-embedded-runner/compact-reasons.ts b/src/agents/pi-embedded-runner/compact-reasons.ts index 1772faeaaa2..642889cbc4d 100644 --- a/src/agents/pi-embedded-runner/compact-reasons.ts +++ b/src/agents/pi-embedded-runner/compact-reasons.ts @@ -1,5 +1,7 @@ +import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; + function isGenericCompactionCancelledReason(reason: string): boolean { - const normalized = reason.trim().toLowerCase(); + const normalized = normalizeLowercaseStringOrEmpty(reason); return normalized === "compaction cancelled" || normalized === "error: compaction cancelled"; } @@ -14,7 +16,7 @@ export function resolveCompactionFailureReason(params: { } export function classifyCompactionReason(reason?: string): string { - const text = (reason ?? "").trim().toLowerCase(); + const text = normalizeLowercaseStringOrEmpty(reason); if (!text) { return "unknown"; } diff --git a/src/agents/tools/sessions-access.ts b/src/agents/tools/sessions-access.ts index 47bd0806f7b..f456f2efeea 100644 --- a/src/agents/tools/sessions-access.ts +++ b/src/agents/tools/sessions-access.ts @@ -1,5 +1,6 @@ import type { OpenClawConfig } from "../../config/config.js"; import { isSubagentSessionKey, resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; +import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; import { listSpawnedSessionKeys, resolveInternalSessionKey, @@ -23,7 +24,7 @@ export type SessionAccessResult = export function resolveSessionToolsVisibility(cfg: OpenClawConfig): SessionToolsVisibility { const raw = (cfg.tools as { sessions?: { visibility?: unknown } } | undefined)?.sessions ?.visibility; - const value = typeof raw === "string" ? raw.trim().toLowerCase() : ""; + const value = normalizeLowercaseStringOrEmpty(raw); if (value === "self" || value === "tree" || value === "agent" || value === "all") { return value; } diff --git a/src/auto-reply/command-auth.ts b/src/auto-reply/command-auth.ts index da6fa78f881..9680b63db06 100644 --- a/src/auto-reply/command-auth.ts +++ b/src/auto-reply/command-auth.ts @@ -2,6 +2,7 @@ import { getChannelPlugin, listChannelPlugins } from "../channels/plugins/index. import type { ChannelId, ChannelPlugin } from "../channels/plugins/types.js"; import { normalizeAnyChannelId } from "../channels/registry.js"; import type { OpenClawConfig } from "../config/config.js"; +import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; import { normalizeStringEntries } from "../shared/string-normalization.js"; import { INTERNAL_MESSAGE_CHANNEL, @@ -466,7 +467,7 @@ function shouldUseFromAsSenderFallback(params: { if (!from) { return false; } - const chatType = (params.chatType ?? "").trim().toLowerCase(); + const chatType = normalizeLowercaseStringOrEmpty(params.chatType); if (chatType && chatType !== "direct") { return false; } diff --git a/src/auto-reply/reply/commands-context.ts b/src/auto-reply/reply/commands-context.ts index 1c5056b4b46..36235167249 100644 --- a/src/auto-reply/reply/commands-context.ts +++ b/src/auto-reply/reply/commands-context.ts @@ -1,4 +1,5 @@ import type { OpenClawConfig } from "../../config/config.js"; +import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; import { resolveCommandAuthorization } from "../command-auth.js"; import { normalizeCommandBody } from "../commands-registry.js"; import type { MsgContext } from "../templating.js"; @@ -20,8 +21,8 @@ export function buildCommandContext(params: { cfg, commandAuthorized: params.commandAuthorized, }); - const surface = (ctx.Surface ?? ctx.Provider ?? "").trim().toLowerCase(); - const channel = (ctx.Provider ?? surface).trim().toLowerCase(); + const surface = normalizeLowercaseStringOrEmpty(ctx.Surface ?? ctx.Provider); + const channel = normalizeLowercaseStringOrEmpty(ctx.Provider ?? surface); const abortKey = sessionKey ?? (auth.from || undefined) ?? (auth.to || undefined); const rawBodyNormalized = triggerBodyNormalized; const commandBodyNormalized = normalizeCommandBody( diff --git a/src/auto-reply/reply/session-delivery.ts b/src/auto-reply/reply/session-delivery.ts index 6185b6f7c3c..bc18aab3d5f 100644 --- a/src/auto-reply/reply/session-delivery.ts +++ b/src/auto-reply/reply/session-delivery.ts @@ -1,7 +1,10 @@ import type { SessionEntry } from "../../config/sessions.js"; import { buildAgentMainSessionKey } from "../../routing/session-key.js"; import { parseAgentSessionKey } from "../../sessions/session-key-utils.js"; -import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import { + normalizeLowercaseStringOrEmpty, + normalizeOptionalString, +} from "../../shared/string-coerce.js"; import { deliveryContextFromSession, deliveryContextKey, @@ -34,9 +37,9 @@ function resolveSessionKeyChannelHint(sessionKey?: string): string | undefined { function isMainSessionKey(sessionKey?: string): boolean { const parsed = parseAgentSessionKey(sessionKey); if (!parsed) { - return (sessionKey ?? "").trim().toLowerCase() === "main"; + return normalizeLowercaseStringOrEmpty(sessionKey) === "main"; } - return parsed.rest.trim().toLowerCase() === "main"; + return normalizeLowercaseStringOrEmpty(parsed.rest) === "main"; } const DIRECT_SESSION_MARKERS = new Set(["direct", "dm"]); @@ -59,7 +62,7 @@ function hasStrictDirectSessionTail(parts: string[], markerIndex: number): boole } function isDirectSessionKey(sessionKey?: string): boolean { - const raw = (sessionKey ?? "").trim().toLowerCase(); + const raw = normalizeLowercaseStringOrEmpty(sessionKey); if (!raw) { return false; } diff --git a/src/auto-reply/tool-meta.ts b/src/auto-reply/tool-meta.ts index ce929284ece..5083ef4e10e 100644 --- a/src/auto-reply/tool-meta.ts +++ b/src/auto-reply/tool-meta.ts @@ -1,4 +1,5 @@ import { formatToolSummary, resolveToolDisplay } from "../agents/tool-display.js"; +import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; import { shortenHomeInString, shortenHomePath } from "../utils.js"; type ToolAggregateOptions = { @@ -80,7 +81,7 @@ function formatMetaForDisplay( meta: string, markdown?: boolean, ): string { - const normalized = (toolName ?? "").trim().toLowerCase(); + const normalized = normalizeLowercaseStringOrEmpty(toolName); if (normalized === "exec" || normalized === "bash") { const { flags, body } = splitExecFlags(meta); if (flags.length > 0) {