refactor: dedupe lowercase helper readers

This commit is contained in:
Peter Steinberger
2026-04-07 14:48:12 +01:00
parent eba04199f8
commit 948d139399
13 changed files with 82 additions and 33 deletions

View File

@@ -2,6 +2,10 @@ import path from "node:path";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { OpenClawConfig } from "../config/config.js";
import { asNullableRecord } from "../shared/record-coerce.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "../shared/string-coerce.js";
export const DEFAULT_MEMORY_DREAMING_ENABLED = false;
export const DEFAULT_MEMORY_DREAMING_TIMEZONE = undefined;
@@ -190,7 +194,7 @@ function normalizeBoolean(value: unknown, fallback: boolean): boolean {
return value;
}
if (typeof value === "string") {
const normalized = value.trim().toLowerCase();
const normalized = normalizeLowercaseStringOrEmpty(value);
if (normalized === "true") {
return true;
}
@@ -591,7 +595,7 @@ export function resolveMemoryDreamingWorkspaces(cfg: OpenClawConfig): MemoryDrea
if (!entry || typeof entry !== "object" || typeof entry.id !== "string") {
continue;
}
const id = entry.id.trim().toLowerCase();
const id = normalizeOptionalLowercaseString(entry.id);
if (!id || seenAgents.has(id)) {
continue;
}

View File

@@ -1,3 +1,5 @@
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
const MEMORY_MULTIMODAL_SPECS = {
image: {
labelPrefix: "Image file",
@@ -73,7 +75,7 @@ export function buildMemoryMultimodalLabel(
}
export function buildCaseInsensitiveExtensionGlob(extension: string): string {
const normalized = extension.trim().replace(/^\./, "").toLowerCase();
const normalized = normalizeLowercaseStringOrEmpty(extension).replace(/^\./, "");
if (!normalized) {
return "*";
}
@@ -88,7 +90,7 @@ export function classifyMemoryMultimodalPath(
if (!isMemoryMultimodalEnabled(settings)) {
return null;
}
const lower = filePath.trim().toLowerCase();
const lower = normalizeLowercaseStringOrEmpty(filePath);
for (const modality of settings.modalities) {
for (const extension of getMemoryMultimodalExtensions(modality)) {
if (lower.endsWith(extension)) {

View File

@@ -1,5 +1,6 @@
import { formatErrorMessage } from "../../infra/errors.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
const log = createSubsystemLogger("memory");
@@ -52,7 +53,7 @@ export function parseQmdQueryJson(stdout: string, stderr: string): QmdQueryResul
function isQmdNoResultsOutput(raw: string): boolean {
const lines = raw
.split(/\r?\n/)
.map((line) => line.trim().toLowerCase().replace(/\s+/g, " "))
.map((line) => normalizeLowercaseStringOrEmpty(line).replace(/\s+/g, " "))
.filter((line) => line.length > 0);
return lines.some((line) => isQmdNoResultsLine(line));
}

View File

@@ -1,4 +1,8 @@
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "../../shared/string-coerce.js";
import type { ResolvedQmdConfig } from "./backend-config.js";
type ParsedQmdSessionScope = {
@@ -15,7 +19,7 @@ export function isQmdScopeAllowed(scope: ResolvedQmdConfig["scope"], sessionKey?
const channel = parsed.channel;
const chatType = parsed.chatType;
const normalizedKey = parsed.normalizedKey ?? "";
const rawKey = sessionKey?.trim().toLowerCase() ?? "";
const rawKey = normalizeLowercaseStringOrEmpty(sessionKey);
for (const rule of scope.rules ?? []) {
if (!rule) {
continue;
@@ -27,8 +31,8 @@ export function isQmdScopeAllowed(scope: ResolvedQmdConfig["scope"], sessionKey?
if (match.chatType && match.chatType !== chatType) {
continue;
}
const normalizedPrefix = match.keyPrefix?.trim().toLowerCase() || undefined;
const rawPrefix = match.rawKeyPrefix?.trim().toLowerCase() || undefined;
const normalizedPrefix = normalizeOptionalLowercaseString(match.keyPrefix);
const rawPrefix = normalizeOptionalLowercaseString(match.rawKeyPrefix);
if (rawPrefix && !rawKey.startsWith(rawPrefix)) {
continue;

View File

@@ -8,6 +8,8 @@
* This module extracts meaningful keywords from such queries to improve FTS results.
*/
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
// Common stop words that don't add search value
const STOP_WORDS_EN = new Set([
// Articles and determiners
@@ -673,7 +675,7 @@ function isValidKeyword(token: string): boolean {
function tokenize(text: string, opts?: { ftsTokenizer?: "unicode61" | "trigram" }): string[] {
const useTrigram = opts?.ftsTokenizer === "trigram";
const tokens: string[] = [];
const normalized = text.toLowerCase().trim();
const normalized = normalizeLowercaseStringOrEmpty(text);
// Split into segments (English words, Chinese character sequences, etc.)
const segments = normalized.split(/[\s\p{P}]+/u).filter(Boolean);