refactor: dedupe lowercase normalizer readers

This commit is contained in:
Peter Steinberger
2026-04-07 10:57:48 +01:00
parent af1cf77b16
commit 4dc16e1567
9 changed files with 39 additions and 22 deletions

View File

@@ -2,6 +2,7 @@ import type { OpenClawConfig } from "../config/config.js";
import type { SessionAcpMeta } from "../config/sessions/types.js";
import { logVerbose } from "../globals.js";
import { formatErrorMessage } from "../infra/errors.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import { getAcpSessionManager } from "./control-plane/manager.js";
import { resolveConfiguredAcpBindingSpecBySessionKey } from "./persistent-bindings.resolve.js";
import {
@@ -21,8 +22,10 @@ function sessionMatchesConfiguredBinding(params: {
return false;
}
const desiredAgent = (params.spec.acpAgentId ?? params.spec.agentId).trim().toLowerCase();
const currentAgent = (params.meta.agent ?? "").trim().toLowerCase();
const desiredAgent = normalizeLowercaseStringOrEmpty(
params.spec.acpAgentId ?? params.spec.agentId,
);
const currentAgent = normalizeLowercaseStringOrEmpty(params.meta.agent);
if (!currentAgent || currentAgent !== desiredAgent) {
return false;
}

View File

@@ -1,14 +1,18 @@
import type { MsgContext } from "../../auto-reply/templating.js";
import { getChannelPlugin, listChannelPlugins } from "../../channels/plugins/index.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "../../shared/string-coerce.js";
import { normalizeMessageChannel } from "../../utils/message-channel.js";
function resolveExplicitSessionKeyNormalizerCandidates(
sessionKey: string,
ctx: Pick<MsgContext, "From" | "Provider" | "Surface">,
): string[] {
const normalizedProvider = ctx.Provider?.trim().toLowerCase();
const normalizedSurface = ctx.Surface?.trim().toLowerCase();
const normalizedFrom = (ctx.From ?? "").trim().toLowerCase();
const normalizedProvider = normalizeOptionalLowercaseString(ctx.Provider);
const normalizedSurface = normalizeOptionalLowercaseString(ctx.Surface);
const normalizedFrom = normalizeLowercaseStringOrEmpty(ctx.From);
const candidates = new Set<string>();
const maybeAdd = (value?: string | null) => {
const normalized = normalizeMessageChannel(value);
@@ -32,12 +36,12 @@ function resolveExplicitSessionKeyNormalizerCandidates(
}
export function normalizeExplicitSessionKey(sessionKey: string, ctx: MsgContext): string {
const normalized = sessionKey.trim().toLowerCase();
const normalized = normalizeLowercaseStringOrEmpty(sessionKey);
for (const channelId of resolveExplicitSessionKeyNormalizerCandidates(normalized, ctx)) {
const normalize = getChannelPlugin(channelId)?.messaging?.normalizeExplicitSessionKey;
const next = normalize?.({ sessionKey: normalized, ctx });
if (typeof next === "string" && next.trim()) {
return next.trim().toLowerCase();
return normalizeLowercaseStringOrEmpty(next);
}
}
return normalized;

View File

@@ -13,6 +13,7 @@ import {
isPrivateOrLoopbackIpAddress,
normalizeIpAddress,
} from "../shared/net/ip.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
/**
* Pick the primary non-internal IPv4 address (LAN IP).
@@ -26,7 +27,7 @@ export function pickPrimaryLanIPv4(): string | undefined {
}
export function normalizeHostHeader(hostHeader?: string): string {
return (hostHeader ?? "").trim().toLowerCase();
return normalizeLowercaseStringOrEmpty(hostHeader);
}
export function resolveHostName(hostHeader?: string): string {

View File

@@ -25,7 +25,10 @@ import { resolveSendPolicy } from "../../sessions/send-policy.js";
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
import { resolveAssistantMessagePhase } from "../../shared/chat-message-content.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
} from "../../shared/string-coerce.js";
import {
stripInlineDirectiveTagsForDisplay,
stripInlineDirectiveTagsFromMessageForDisplay,
@@ -228,9 +231,9 @@ function resolveChatSendOriginatingRoute(params: {
.filter(Boolean);
const sessionScopeHead = sessionScopeParts[0];
const sessionChannelHint = normalizeMessageChannel(sessionScopeHead);
const normalizedSessionScopeHead = (sessionScopeHead ?? "").trim().toLowerCase();
const normalizedSessionScopeHead = normalizeLowercaseStringOrEmpty(sessionScopeHead);
const sessionPeerShapeCandidates = [sessionScopeParts[1], sessionScopeParts[2]]
.map((part) => (part ?? "").trim().toLowerCase())
.map((part) => normalizeLowercaseStringOrEmpty(part))
.filter(Boolean);
const isChannelAgnosticSessionScope = CHANNEL_AGNOSTIC_SESSION_SCOPES.has(
normalizedSessionScopeHead,
@@ -247,7 +250,7 @@ function resolveChatSendOriginatingRoute(params: {
const hasClientMetadata =
(typeof params.client?.mode === "string" && params.client.mode.trim().length > 0) ||
(typeof params.client?.id === "string" && params.client.id.trim().length > 0);
const configuredMainKey = (params.mainKey ?? "main").trim().toLowerCase();
const configuredMainKey = normalizeLowercaseStringOrEmpty(params.mainKey ?? "main");
const isConfiguredMainSessionScope =
normalizedSessionScopeHead.length > 0 && normalizedSessionScopeHead === configuredMainKey;
const canInheritConfiguredMainRoute =

View File

@@ -19,6 +19,7 @@ import {
resolveApnsAuthConfigFromEnv,
resolveApnsRelayConfigFromEnv,
} from "../../infra/push-apns.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import {
buildCanvasScopedHostUrl,
CANVAS_CAPABILITY_TTL_MS,
@@ -150,7 +151,7 @@ function shouldQueueAsPendingForegroundAction(params: {
command: string;
error: unknown;
}): boolean {
const platform = (params.platform ?? "").trim().toLowerCase();
const platform = normalizeLowercaseStringOrEmpty(params.platform);
if (!platform.startsWith("ios") && !platform.startsWith("ipados")) {
return false;
}

View File

@@ -1,4 +1,5 @@
import { parseAgentSessionKey } from "../sessions/session-key-utils.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import { asString, extractTextFromMessage, isCommandMessage } from "./tui-formatters.js";
import { TuiStreamAssembler } from "./tui-stream-assembler.js";
import type { AgentEvent, BtwEvent, ChatEvent, TuiStateAccess } from "./tui-types.js";
@@ -192,8 +193,8 @@ export function createEventHandlers(context: EventHandlerContext) {
};
const isSameSessionKey = (left: string | undefined, right: string | undefined): boolean => {
const normalizedLeft = (left ?? "").trim().toLowerCase();
const normalizedRight = (right ?? "").trim().toLowerCase();
const normalizedLeft = normalizeLowercaseStringOrEmpty(left);
const normalizedRight = normalizeLowercaseStringOrEmpty(right);
if (!normalizedLeft || !normalizedRight) {
return false;
}