refactor: dedupe session helper readers

This commit is contained in:
Peter Steinberger
2026-04-07 07:18:33 +01:00
parent 972fe9286d
commit dfec7d7f80
12 changed files with 36 additions and 58 deletions

View File

@@ -11,7 +11,7 @@ import {
parseAgentSessionKey,
resolveAgentIdFromSessionKey,
} from "../routing/session-key.js";
import { readStringValue } from "../shared/string-coerce.js";
import { normalizeOptionalString, readStringValue } from "../shared/string-coerce.js";
import { resolveUserPath } from "../utils.js";
import { resolveEffectiveAgentSkillFilter } from "./skills/agent-filter.js";
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
@@ -172,18 +172,13 @@ export function resolveAgentSkillsFilter(
function resolveModelPrimary(raw: unknown): string | undefined {
if (typeof raw === "string") {
const trimmed = raw.trim();
return trimmed || undefined;
return normalizeOptionalString(raw);
}
if (!raw || typeof raw !== "object") {
return undefined;
}
const primary = (raw as { primary?: unknown }).primary;
if (typeof primary !== "string") {
return undefined;
}
const trimmed = primary.trim();
return trimmed || undefined;
return normalizeOptionalString(primary);
}
export function resolveAgentExplicitModelPrimary(

View File

@@ -1,12 +1,9 @@
import type { OpenClawConfig } from "../../config/config.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { AuthProfileStore } from "./types.js";
function trimOptionalString(value: string | null | undefined): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed || undefined;
return normalizeOptionalString(value);
}
function resolveStoredMetadata(store: AuthProfileStore | undefined, profileId: string) {

View File

@@ -1,12 +1,12 @@
import crypto from "node:crypto";
import type { CliSessionBinding, SessionEntry } from "../config/sessions.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { normalizeProviderId } from "./model-selection.js";
const CLAUDE_CLI_BACKEND_ID = "claude-cli";
function trimOptional(value: string | undefined): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
export function hashCliSessionText(value: string | undefined): string | undefined {
@@ -37,11 +37,12 @@ export function getCliSessionBinding(
};
}
const fromMap = entry.cliSessionIds?.[normalized];
if (fromMap?.trim()) {
return { sessionId: fromMap.trim() };
const normalizedFromMap = normalizeOptionalString(fromMap);
if (normalizedFromMap) {
return { sessionId: normalizedFromMap };
}
if (normalized === CLAUDE_CLI_BACKEND_ID) {
const legacy = entry.claudeCliSessionId?.trim();
const legacy = normalizeOptionalString(entry.claudeCliSessionId);
if (legacy) {
return { sessionId: legacy };
}

View File

@@ -1,5 +1,6 @@
import crypto from "node:crypto";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
export type OwnerDisplaySetting = {
ownerDisplay?: "raw" | "hash";
@@ -12,8 +13,7 @@ export type OwnerDisplaySecretResolution = {
};
function trimToUndefined(value?: string): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
/**

View File

@@ -1,5 +1,5 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { readStringValue } from "../shared/string-coerce.js";
import { normalizeOptionalString, readStringValue } from "../shared/string-coerce.js";
import { extractToolCallsFromAssistant, extractToolResultId } from "./tool-call-id.js";
const TOOL_CALL_NAME_MAX_CHARS = 64;
@@ -153,11 +153,7 @@ function makeMissingToolResult(params: {
}
function trimNonEmptyString(value: unknown): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed || undefined;
return normalizeOptionalString(value);
}
function normalizeToolResultName(

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "../config/config.js";
import { normalizeAgentId, parseAgentSessionKey } from "../routing/session-key.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { resolveAgentWorkspaceDir } from "./agent-scope.js";
export type SpawnedRunMetadata = {
@@ -26,11 +27,7 @@ export type NormalizedSpawnedRunMetadata = {
};
function normalizeOptionalText(value?: string | null): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed || undefined;
return normalizeOptionalString(value);
}
export function normalizeSpawnedRunMetadata(

View File

@@ -34,6 +34,7 @@ export {
stripToolMessages,
} from "./chat-history-text.js";
import { type OpenClawConfig, loadConfig } from "../../config/config.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
export type SessionKind = "main" | "group" | "cron" | "hook" | "node" | "other";
@@ -87,8 +88,7 @@ export type SessionListRow = {
};
function normalizeKey(value?: string) {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
export function resolveSessionToolContext(opts?: {

View File

@@ -3,6 +3,7 @@ import { callGateway } from "../../gateway/call.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { isAcpSessionKey, normalizeMainKey } from "../../routing/session-key.js";
import { looksLikeSessionId } from "../../sessions/session-id.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
type GatewayCaller = typeof callGateway;
@@ -15,8 +16,7 @@ let sessionsResolutionDeps: {
} = defaultSessionsResolutionDeps;
function normalizeKey(value?: string) {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
export function resolveMainSessionAlias(cfg: OpenClawConfig) {

View File

@@ -2,16 +2,13 @@ import { normalizeChatType } from "../../channels/chat-type.js";
import { getBundledChannelPlugin } from "../../channels/plugins/bundled.js";
import { getLoadedChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
import { resolveSenderLabel } from "../../channels/sender-label.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { EnvelopeFormatOptions } from "../envelope.js";
import { formatEnvelopeTimestamp } from "../envelope.js";
import type { TemplateContext } from "../templating.js";
function safeTrim(value: unknown): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
function formatConversationTimestamp(

View File

@@ -1,5 +1,6 @@
import { resolveConfigPath, resolveGatewayPort } from "../config/paths.js";
import type { OpenClawConfig } from "../config/types.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { isSecureWebSocketUrl } from "./net.js";
export type GatewayConnectionDetails = {
@@ -17,8 +18,7 @@ type GatewayConnectionDetailResolvers = {
};
function trimToUndefined(value: string | undefined): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
export function buildGatewayConnectionDetailsWithResolvers(
@@ -43,16 +43,12 @@ export function buildGatewayConnectionDetailsWithResolvers(
const bindMode = config.gateway?.bind ?? "loopback";
const scheme = tlsEnabled ? "wss" : "ws";
const localUrl = `${scheme}://127.0.0.1:${localPort}`;
const cliUrlOverride =
typeof options.url === "string" && options.url.trim().length > 0
? options.url.trim()
: undefined;
const cliUrlOverride = normalizeOptionalString(options.url);
const envUrlOverride = cliUrlOverride
? undefined
: trimToUndefined(process.env.OPENCLAW_GATEWAY_URL);
const urlOverride = cliUrlOverride ?? envUrlOverride;
const remoteUrl =
typeof remote?.url === "string" && remote.url.trim().length > 0 ? remote.url.trim() : undefined;
const remoteUrl = normalizeOptionalString(remote?.url);
const remoteMisconfigured = isRemoteMode && !urlOverride && !remoteUrl;
const urlSourceHint =
options.urlSource ?? (cliUrlOverride ? "cli" : envUrlOverride ? "env" : undefined);

View File

@@ -12,6 +12,7 @@ import { resolvePluginWebSearchConfig } from "../config/plugin-web-search-config
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveManifestContractPluginIds } from "../plugins/manifest-registry.js";
import { normalizeProviderModelIdWithPlugin } from "../plugins/provider-runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
clearGatewayModelPricingCacheState,
getCachedGatewayModelPricing,
@@ -68,11 +69,9 @@ function clearRefreshTimer(): void {
function listLikePrimary(value: ModelListLike): string | undefined {
if (typeof value === "string") {
const trimmed = value.trim();
return trimmed || undefined;
return normalizeOptionalString(value);
}
const trimmed = value?.primary?.trim();
return trimmed || undefined;
return normalizeOptionalString(value?.primary);
}
function listLikeFallbacks(value: ModelListLike): string[] {
@@ -82,8 +81,8 @@ function listLikeFallbacks(value: ModelListLike): string[] {
return Array.isArray(value.fallbacks)
? value.fallbacks
.filter((entry): entry is string => typeof entry === "string")
.map((entry) => entry.trim())
.filter(Boolean)
.map((entry) => normalizeOptionalString(entry))
.filter((entry): entry is string => Boolean(entry))
: [];
}

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import { loadConfig } from "../config/config.js";
import { loadSessionStore } from "../config/sessions.js";
import { onSessionTranscriptUpdate } from "../sessions/transcript-events.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { AuthRateLimiter } from "./auth-rate-limit.js";
import type { ResolvedGatewayAuth } from "./auth.js";
import {
@@ -36,7 +37,7 @@ function resolveSessionHistoryPath(req: IncomingMessage): string | null {
return null;
}
try {
return decodeURIComponent(match[1] ?? "").trim() || null;
return normalizeOptionalString(decodeURIComponent(match[1] ?? "")) ?? null;
} catch {
return "";
}
@@ -65,12 +66,11 @@ function resolveLimit(req: IncomingMessage): number | undefined {
function resolveCursor(req: IncomingMessage): string | undefined {
const raw = getRequestUrl(req).searchParams.get("cursor");
const trimmed = raw?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(raw);
}
function canonicalizePath(value: string | undefined): string | undefined {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
return undefined;
}