From 5ebef46183a714edf4b8a282526ba9b7238b0b35 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 18:16:53 +0100 Subject: [PATCH] perf: speed up hot test paths --- src/config/redact-snapshot.ts | 3 +- src/config/schema.hints.ts | 46 +------------------ src/config/sensitive-paths.ts | 46 +++++++++++++++++++ src/infra/os-summary.ts | 11 ++++- .../host/session-files.test.ts | 2 +- src/plugins/config-state.ts | 8 ++++ src/trajectory/metadata.test.ts | 22 ++++++++- 7 files changed, 90 insertions(+), 48 deletions(-) create mode 100644 src/config/sensitive-paths.ts diff --git a/src/config/redact-snapshot.ts b/src/config/redact-snapshot.ts index f50d8d5eb76..9e9b9d98dfe 100644 --- a/src/config/redact-snapshot.ts +++ b/src/config/redact-snapshot.ts @@ -1,4 +1,5 @@ import { createSubsystemLogger } from "../logging/subsystem.js"; +import { type ConfigUiHints } from "../shared/config-ui-hints-types.js"; import { hasSensitiveUrlHintTag, isSensitiveUrlConfigPath, @@ -10,7 +11,7 @@ import { shouldFallbackToStructuredRawRedaction, } from "./redact-snapshot.raw.js"; import { isSecretRefShape, redactSecretRefId } from "./redact-snapshot.secret-ref.js"; -import { isSensitiveConfigPath, type ConfigUiHints } from "./schema.hints.js"; +import { isSensitiveConfigPath } from "./sensitive-paths.js"; import type { ConfigFileSnapshot } from "./types.openclaw.js"; const log = createSubsystemLogger("config/redaction"); diff --git a/src/config/schema.hints.ts b/src/config/schema.hints.ts index 1bd8a154af3..9fe833bf830 100644 --- a/src/config/schema.hints.ts +++ b/src/config/schema.hints.ts @@ -5,10 +5,10 @@ import { isSensitiveUrlConfigPath, SENSITIVE_URL_HINT_TAG, } from "../shared/net/redact-sensitive-url.js"; -import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; import { FIELD_HELP } from "./schema.help.js"; import { FIELD_LABELS } from "./schema.labels.js"; import { applyDerivedTags } from "./schema.tags.js"; +import { isSensitiveConfigPath } from "./sensitive-paths.js"; import { sensitive } from "./zod-schema.sensitive.js"; let log: ReturnType | null = null; @@ -111,49 +111,7 @@ export function isPluginOwnedChannelHintPath(path: string): boolean { return !isKernelOwnedChannelHintPath(path); } -/** - * Non-sensitive field names that happen to match sensitive patterns. - * These are explicitly excluded from redaction (plugin config) and - * warnings about not being marked sensitive (base config). - */ -const SENSITIVE_KEY_WHITELIST_SUFFIXES = [ - "maxtokens", - "maxoutputtokens", - "maxinputtokens", - "maxcompletiontokens", - "contexttokens", - "totaltokens", - "tokencount", - "tokenlimit", - "tokenbudget", - "passwordFile", -] as const; -const NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES = SENSITIVE_KEY_WHITELIST_SUFFIXES.map((suffix) => - normalizeLowercaseStringOrEmpty(suffix), -); - -const SENSITIVE_PATTERNS = [ - /token$/i, - /password/i, - /secret/i, - /api.?key/i, - /encrypt.?key/i, - /private.?key/i, - /serviceaccount(?:ref)?$/i, -]; - -function isWhitelistedSensitivePath(path: string): boolean { - const lowerPath = normalizeLowercaseStringOrEmpty(path); - return NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES.some((suffix) => lowerPath.endsWith(suffix)); -} - -function matchesSensitivePattern(path: string): boolean { - return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path)); -} - -export function isSensitiveConfigPath(path: string): boolean { - return !isWhitelistedSensitivePath(path) && matchesSensitivePattern(path); -} +export { isSensitiveConfigPath }; export function buildBaseHints(): ConfigUiHints { const hints: ConfigUiHints = {}; diff --git a/src/config/sensitive-paths.ts b/src/config/sensitive-paths.ts new file mode 100644 index 00000000000..86e50fca0f5 --- /dev/null +++ b/src/config/sensitive-paths.ts @@ -0,0 +1,46 @@ +import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; + +/** + * Non-sensitive field names that happen to match sensitive patterns. + * These are explicitly excluded from redaction (plugin config) and + * warnings about not being marked sensitive (base config). + */ +const SENSITIVE_KEY_WHITELIST_SUFFIXES = [ + "maxtokens", + "maxoutputtokens", + "maxinputtokens", + "maxcompletiontokens", + "contexttokens", + "totaltokens", + "tokencount", + "tokenlimit", + "tokenbudget", + "passwordFile", +] as const; + +const NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES = SENSITIVE_KEY_WHITELIST_SUFFIXES.map((suffix) => + normalizeLowercaseStringOrEmpty(suffix), +); + +const SENSITIVE_PATTERNS = [ + /token$/i, + /password/i, + /secret/i, + /api.?key/i, + /encrypt.?key/i, + /private.?key/i, + /serviceaccount(?:ref)?$/i, +]; + +function isWhitelistedSensitivePath(path: string): boolean { + const lowerPath = normalizeLowercaseStringOrEmpty(path); + return NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES.some((suffix) => lowerPath.endsWith(suffix)); +} + +function matchesSensitivePattern(path: string): boolean { + return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path)); +} + +export function isSensitiveConfigPath(path: string): boolean { + return !isWhitelistedSensitivePath(path) && matchesSensitivePattern(path); +} diff --git a/src/infra/os-summary.ts b/src/infra/os-summary.ts index 0c5fdad0d36..867d10265b4 100644 --- a/src/infra/os-summary.ts +++ b/src/infra/os-summary.ts @@ -9,6 +9,8 @@ export type OsSummary = { label: string; }; +const cachedOsSummaryByKey = new Map(); + function macosVersion(): string { const res = spawnSync("sw_vers", ["-productVersion"], { encoding: "utf-8" }); const out = normalizeOptionalString(res.stdout) ?? ""; @@ -19,6 +21,11 @@ export function resolveOsSummary(): OsSummary { const platform = os.platform(); const release = os.release(); const arch = os.arch(); + const cacheKey = `${platform}\0${release}\0${arch}`; + const cached = cachedOsSummaryByKey.get(cacheKey); + if (cached) { + return cached; + } const label = (() => { if (platform === "darwin") { return `macos ${macosVersion()} (${arch})`; @@ -28,5 +35,7 @@ export function resolveOsSummary(): OsSummary { } return `${platform} ${release} (${arch})`; })(); - return { platform, arch, release, label }; + const summary = { platform, arch, release, label }; + cachedOsSummaryByKey.set(cacheKey, summary); + return summary; } diff --git a/src/memory-host-sdk/host/session-files.test.ts b/src/memory-host-sdk/host/session-files.test.ts index 20fd3790a20..73c6e1b051f 100644 --- a/src/memory-host-sdk/host/session-files.test.ts +++ b/src/memory-host-sdk/host/session-files.test.ts @@ -301,7 +301,7 @@ describe("buildSessionEntry", () => { it("does not split surrogate pairs when hard-wrapping astral unicode without spaces", async () => { const astralChar = "\u{20000}"; - const giantToken = astralChar.repeat(1200); + const giantToken = astralChar.repeat(410); const jsonlLines = [ JSON.stringify({ type: "message", diff --git a/src/plugins/config-state.ts b/src/plugins/config-state.ts index 5830249123b..a72ed6ef224 100644 --- a/src/plugins/config-state.ts +++ b/src/plugins/config-state.ts @@ -41,6 +41,10 @@ const BUILT_IN_PLUGIN_ALIAS_FALLBACKS: ReadonlyArray([ + ...BUILT_IN_PLUGIN_ALIAS_FALLBACKS, + ...BUILT_IN_PLUGIN_ALIAS_FALLBACKS.map(([, pluginId]) => [pluginId, pluginId] as const), +]); function getBundledPluginAliasLookup(): ReadonlyMap { if (bundledPluginAliasLookupCache) { @@ -79,6 +83,10 @@ function getBundledPluginAliasLookup(): ReadonlyMap { export function normalizePluginId(id: string): string { const trimmed = normalizeOptionalString(id) ?? ""; const normalized = normalizeOptionalLowercaseString(trimmed) ?? ""; + const builtInAlias = BUILT_IN_PLUGIN_ALIAS_LOOKUP.get(normalized); + if (builtInAlias) { + return builtInAlias; + } return getBundledPluginAliasLookup().get(normalized) ?? trimmed; } diff --git a/src/trajectory/metadata.test.ts b/src/trajectory/metadata.test.ts index 79d3aff8c29..f4b9da362d9 100644 --- a/src/trajectory/metadata.test.ts +++ b/src/trajectory/metadata.test.ts @@ -1,7 +1,27 @@ -import { afterEach, describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { REDACTED_SENTINEL } from "../config/redact-snapshot.js"; import { createEmptyPluginRegistry } from "../plugins/registry-empty.js"; import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js"; + +const loadPluginManifestRegistry = vi.hoisted(() => vi.fn(() => ({ plugins: [] }))); + +vi.mock("../infra/git-commit.js", () => ({ + resolveCommitHash: () => "abcdef0", +})); + +vi.mock("../infra/os-summary.js", () => ({ + resolveOsSummary: () => ({ + platform: "darwin", + arch: "arm64", + release: "test-release", + label: "test-os", + }), +})); + +vi.mock("../plugins/manifest-registry.js", () => ({ + loadPluginManifestRegistry, +})); + import { buildTrajectoryArtifacts, buildTrajectoryRunMetadata } from "./metadata.js"; afterEach(() => {