refactor: dedupe lowercased readers

This commit is contained in:
Peter Steinberger
2026-04-07 08:15:36 +01:00
parent 763dc614c0
commit a5ff85f01c
12 changed files with 28 additions and 24 deletions

View File

@@ -1,5 +1,6 @@
import { resolveLanguage } from "@pierre/diffs";
import type { FileContents, FileDiffMetadata, SupportedLanguages } from "@pierre/diffs";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import type { DiffViewerPayload } from "./types.js";
const PASSTHROUGH_LANGUAGE_HINTS = new Set<SupportedLanguages>(["ansi", "text"]);
@@ -8,7 +9,7 @@ type DiffPayloadFile = FileContents | FileDiffMetadata;
export async function normalizeSupportedLanguageHint(
value?: string,
): Promise<SupportedLanguages | undefined> {
const normalized = value?.trim();
const normalized = normalizeOptionalString(value);
if (!normalized) {
return undefined;
}

View File

@@ -440,7 +440,7 @@ function buildArtifactContext(
}
function normalizeContextString(value: string | undefined): string | undefined {
const normalized = value?.trim();
const normalized = normalizeOptionalString(value);
return normalized ? normalized : undefined;
}

View File

@@ -3,6 +3,7 @@ import {
deliverTextOrMediaReply,
resolveSendableOutboundReplyParts,
} from "openclaw/plugin-sdk/reply-payload";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import type { OpenClawConfig } from "../runtime-api.js";
import {
createChannelReplyPipeline,
@@ -72,7 +73,7 @@ export function registerGoogleChatWebhookTarget(target: WebhookTarget): () => vo
}
function normalizeAudienceType(value?: string | null): GoogleChatAudienceType | undefined {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "app-url" || normalized === "app_url" || normalized === "app") {
return "app-url";
}

View File

@@ -1,5 +1,6 @@
import type { ReactionTypeEmoji } from "@grammyjs/types";
import { DEFAULT_EMOJIS, type StatusReactionEmojis } from "openclaw/plugin-sdk/channel-feedback";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import type { TelegramChatDetails, TelegramGetChat } from "./bot/types.js";
type StatusReactionEmojiKey = keyof Required<StatusReactionEmojis>;
@@ -114,7 +115,7 @@ const STATUS_REACTION_EMOJI_KEYS: StatusReactionEmojiKey[] = [
];
function normalizeEmoji(value: string | undefined): string | undefined {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
return trimmed ? trimmed : undefined;
}

View File

@@ -1,6 +1,7 @@
import type { ChannelId } from "../channels/plugins/types.js";
import { resolveAccountEntry } from "../routing/account-lookup.js";
import { normalizeAccountId } from "../routing/session-key.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { OpenClawConfig } from "./config.js";
import {
parseToolsBySenderTypedKey,
@@ -207,7 +208,7 @@ function resolveCompiledToolsBySenderPolicy(
}
function normalizeCandidate(value: string | null | undefined, type: SenderKeyType): string {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
return "";
}
@@ -215,7 +216,7 @@ function normalizeCandidate(value: string | null | undefined, type: SenderKeyTyp
}
function normalizeSenderIdCandidates(value: string | null | undefined): string[] {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
return [];
}

View File

@@ -2,6 +2,7 @@ import crypto from "node:crypto";
import type { Skill } from "@mariozechner/pi-coding-agent";
import type { ChatType } from "../../channels/chat-type.js";
import type { ChannelId } from "../../channels/plugins/types.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { DeliveryContext } from "../../utils/delivery-context.js";
import type { TtsAutoMode } from "../types.tts.js";
@@ -235,7 +236,7 @@ export type SessionEntry = {
};
function normalizeRuntimeField(value: string | undefined): string | undefined {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
return trimmed ? trimmed : undefined;
}

View File

@@ -1,4 +1,5 @@
import path from "node:path";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { isDispatchWrapperExecutable } from "./dispatch-wrapper-resolution.js";
import {
analyzeShellCommand,
@@ -149,12 +150,12 @@ function pickExecAllowlistContext(params: ExecAllowlistContext): ExecAllowlistCo
}
function normalizeSkillBinName(value: string | undefined): string | null {
const trimmed = value?.trim().toLowerCase();
const trimmed = normalizeOptionalString(value)?.toLowerCase();
return trimmed && trimmed.length > 0 ? trimmed : null;
}
function normalizeSkillBinResolvedPath(value: string | undefined): string | null {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
return null;
}

View File

@@ -16,7 +16,7 @@ export type ExecSecurity = "deny" | "allowlist" | "full";
export type ExecAsk = "off" | "on-miss" | "always";
export function normalizeExecHost(value?: string | null): ExecHost | null {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "sandbox" || normalized === "gateway" || normalized === "node") {
return normalized;
}
@@ -24,7 +24,7 @@ export function normalizeExecHost(value?: string | null): ExecHost | null {
}
export function normalizeExecTarget(value?: string | null): ExecTarget | null {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "auto") {
return normalized;
}
@@ -35,7 +35,7 @@ export function normalizeExecTarget(value?: string | null): ExecTarget | null {
const toStringOrUndefined = readStringValue;
export function normalizeExecSecurity(value?: string | null): ExecSecurity | null {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "deny" || normalized === "allowlist" || normalized === "full") {
return normalized;
}
@@ -43,7 +43,7 @@ export function normalizeExecSecurity(value?: string | null): ExecSecurity | nul
}
export function normalizeExecAsk(value?: string | null): ExecAsk | null {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "off" || normalized === "on-miss" || normalized === "always") {
return normalized;
}
@@ -193,7 +193,7 @@ export function resolveExecApprovalsSocketPath(): string {
}
function normalizeAllowlistPattern(value: string | undefined): string | null {
const trimmed = value?.trim() ?? "";
const trimmed = normalizeOptionalString(value) ?? "";
return trimmed ? trimmed.toLowerCase() : null;
}

View File

@@ -1,10 +1,11 @@
import { normalizeChatType } from "../channels/chat-type.js";
import type { MediaUnderstandingScopeConfig } from "../config/types.tools.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
export type MediaUnderstandingScopeDecision = "allow" | "deny";
function normalizeDecision(value?: string | null): MediaUnderstandingScopeDecision | undefined {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (normalized === "allow") {
return "allow";
}
@@ -15,7 +16,7 @@ function normalizeDecision(value?: string | null): MediaUnderstandingScopeDecisi
}
function normalizeMatch(value?: string | null): string | undefined {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
return normalized || undefined;
}

View File

@@ -1,4 +1,5 @@
import { logVerbose } from "../globals.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
clearPluginCommands,
clearPluginCommandsForPlugin,
@@ -125,7 +126,7 @@ export function validatePluginCommandDefinition(
export function listPluginInvocationKeys(command: OpenClawPluginCommandDefinition): string[] {
const keys = new Set<string>();
const push = (value: string | undefined) => {
const normalized = value?.trim().toLowerCase();
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (!normalized) {
return;
}

View File

@@ -1,17 +1,13 @@
import type { OpenClawConfig } from "../config/config.js";
import { resolvePluginCapabilityProviders } from "../plugins/capability-provider-runtime.js";
import type { RealtimeTranscriptionProviderPlugin } from "../plugins/types.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { RealtimeTranscriptionProviderId } from "./provider-types.js";
function trimToUndefined(value: string | undefined): string | undefined {
const trimmed = value?.trim().toLowerCase();
return trimmed ? trimmed : undefined;
}
export function normalizeRealtimeTranscriptionProviderId(
providerId: string | undefined,
): RealtimeTranscriptionProviderId | undefined {
return trimToUndefined(providerId);
return normalizeOptionalString(providerId)?.toLowerCase();
}
function resolveRealtimeTranscriptionProviderEntries(

View File

@@ -592,7 +592,7 @@ function pickPreferredRunIdTask(matches: TaskRecord[]): TaskRecord | undefined {
}
function normalizeComparableText(value: string | undefined): string {
return value?.trim() ?? "";
return normalizeOptionalString(value) ?? "";
}
function compareTasksNewestFirst(