refactor: dedupe gateway lowercase helpers

This commit is contained in:
Peter Steinberger
2026-04-07 12:20:52 +01:00
parent 16fad4d7d6
commit f2fa096f14
6 changed files with 28 additions and 16 deletions

View File

@@ -1,6 +1,7 @@
import type { OpenClawConfig } from "../config/config.js";
import { getTailnetHostname } from "../infra/tailscale.js";
import { isIpv6Address, parseCanonicalIpAddress } from "../shared/net/ip.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
export const TAILSCALE_EXPOSURE_OPTIONS = [
{ value: "off", label: "Off", hint: "No Tailscale exposure" },
@@ -56,8 +57,8 @@ export function buildTailnetHttpsOrigin(rawHost: string): string | null {
export function appendAllowedOrigin(existing: string[] | undefined, origin: string): string[] {
const current = existing ?? [];
const normalized = origin.toLowerCase();
if (current.some((entry) => entry.toLowerCase() === normalized)) {
const normalized = normalizeLowercaseStringOrEmpty(origin);
if (current.some((entry) => normalizeLowercaseStringOrEmpty(entry) === normalized)) {
return current;
}
return [...current, origin];

View File

@@ -1,3 +1,5 @@
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
export function hasExpectedToolNonce(text: string, nonceA: string, nonceB: string): boolean {
return text.includes(nonceA) && text.includes(nonceB);
}
@@ -34,7 +36,7 @@ const PROBE_REFUSAL_MARKERS = [
];
export function isLikelyToolNonceRefusal(text: string): boolean {
const lower = text.toLowerCase();
const lower = normalizeLowercaseStringOrEmpty(text);
if (PROBE_REFUSAL_MARKERS.some((marker) => lower.includes(marker))) {
return true;
}
@@ -49,7 +51,7 @@ function hasMalformedToolOutput(text: string): boolean {
if (!trimmed) {
return true;
}
const lower = trimmed.toLowerCase();
const lower = normalizeLowercaseStringOrEmpty(trimmed);
if (trimmed.includes("[object Object]")) {
return true;
}
@@ -91,7 +93,7 @@ export function shouldRetryToolReadProbe(params: {
if (params.provider === "anthropic" && isLikelyToolNonceRefusal(params.text)) {
return true;
}
const lower = params.text.trim().toLowerCase();
const lower = normalizeLowercaseStringOrEmpty(params.text);
if (params.provider === "mistral" && (lower.includes("noncea=") || lower.includes("nonceb="))) {
return true;
}

View File

@@ -35,7 +35,10 @@ import { enqueueSystemEvent } from "../infra/system-events.js";
import { getChildLogger } from "../logging.js";
import { normalizeAgentId, toAgentStoreSessionKey } from "../routing/session-key.js";
import { defaultRuntime } from "../runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../shared/string-coerce.js";
export type GatewayCronState = {
cron: CronService;
@@ -64,7 +67,7 @@ function resolveCronWebhookTarget(params: {
legacyNotify?: boolean;
legacyWebhook?: string;
}): CronWebhookTarget | null {
const mode = normalizeOptionalString(params.delivery?.mode)?.toLowerCase();
const mode = normalizeOptionalLowercaseString(params.delivery?.mode);
if (mode === "webhook") {
const url = normalizeHttpWebhookUrl(params.delivery?.to);
return url ? { url, source: "delivery" } : null;

View File

@@ -7,7 +7,10 @@ import {
} from "../../config/talk.js";
import type { TalkConfigResponse, TalkProviderConfig } from "../../config/types.gateway.js";
import type { OpenClawConfig, TtsConfig, TtsProviderConfigMap } from "../../config/types.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
} from "../../shared/string-coerce.js";
import { canonicalizeSpeechProviderId, getSpeechProvider } from "../../tts/provider-registry.js";
import { synthesizeSpeech, type TtsDirectiveOverrides } from "../../tts/tts.js";
import { ADMIN_SCOPE, TALK_SECRETS_SCOPE } from "../operator-scopes.js";
@@ -55,7 +58,7 @@ function asStringRecord(value: unknown): Record<string, string> | undefined {
}
function normalizeAliasKey(value: string): string {
return value.trim().toLowerCase();
return normalizeLowercaseStringOrEmpty(value);
}
function resolveTalkVoiceId(

View File

@@ -30,6 +30,7 @@ import { applyVerboseOverride, parseVerboseOverride } from "../sessions/level-ov
import { applyModelOverrideToSessionEntry } from "../sessions/model-overrides.js";
import { normalizeSendPolicy } from "../sessions/send-policy.js";
import { parseSessionLabel } from "../sessions/session-label.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import {
ErrorCodes,
type ErrorShape,
@@ -42,7 +43,7 @@ function invalid(message: string): { ok: false; error: ErrorShape } {
}
function normalizeExecSecurity(raw: string): "deny" | "allowlist" | "full" | undefined {
const normalized = raw.trim().toLowerCase();
const normalized = normalizeOptionalLowercaseString(raw);
if (normalized === "deny" || normalized === "allowlist" || normalized === "full") {
return normalized;
}
@@ -50,7 +51,7 @@ function normalizeExecSecurity(raw: string): "deny" | "allowlist" | "full" | und
}
function normalizeExecAsk(raw: string): "off" | "on-miss" | "always" | undefined {
const normalized = raw.trim().toLowerCase();
const normalized = normalizeOptionalLowercaseString(raw);
if (normalized === "off" || normalized === "on-miss" || normalized === "always") {
return normalized;
}
@@ -62,7 +63,7 @@ function supportsSpawnLineage(storeKey: string): boolean {
}
function normalizeSubagentRole(raw: string): "orchestrator" | "leaf" | undefined {
const normalized = raw.trim().toLowerCase();
const normalized = normalizeOptionalLowercaseString(raw);
if (normalized === "orchestrator" || normalized === "leaf") {
return normalized;
}
@@ -70,7 +71,7 @@ function normalizeSubagentRole(raw: string): "orchestrator" | "leaf" | undefined
}
function normalizeSubagentControlScope(raw: string): "children" | "none" | undefined {
const normalized = raw.trim().toLowerCase();
const normalized = normalizeOptionalLowercaseString(raw);
if (normalized === "children" || normalized === "none") {
return normalized;
}

View File

@@ -8,7 +8,10 @@ import { loadConfig } from "../config/config.js";
import { resolveMainSessionKey } from "../config/sessions.js";
import { logWarn } from "../logger.js";
import { isTestDefaultMemorySlotDisabled } from "../plugins/config-state.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../shared/string-coerce.js";
import { normalizeMessageChannel } from "../utils/message-channel.js";
import type { AuthRateLimiter } from "./auth-rate-limit.js";
import type { ResolvedGatewayAuth } from "./auth.js";
@@ -52,8 +55,7 @@ function resolveMemoryToolDisableReasons(cfg: ReturnType<typeof loadConfig>): st
const reasons: string[] = [];
const plugins = cfg.plugins;
const slotRaw = plugins?.slots?.memory;
const slotDisabled =
slotRaw === null || (typeof slotRaw === "string" && slotRaw.trim().toLowerCase() === "none");
const slotDisabled = slotRaw === null || normalizeOptionalLowercaseString(slotRaw) === "none";
const pluginsDisabled = plugins?.enabled === false;
const defaultDisabled = isTestDefaultMemorySlotDisabled(cfg);