From 30e7ecb45435ff1b16e23c9bc46622a05d2b0884 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 26 Aug 2026 21:01:21 -0700 Subject: [PATCH] refactor(memory): remove normalization of fixed search defaults (#130655) --- src/agents/memory-search.test.ts | 31 ++++++----- src/agents/memory-search.ts | 94 ++++---------------------------- 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/src/agents/memory-search.test.ts b/src/agents/memory-search.test.ts index 377e7316f4c3..5b91559b82d0 100644 --- a/src/agents/memory-search.test.ts +++ b/src/agents/memory-search.test.ts @@ -502,7 +502,7 @@ describe("memory search config", () => { }, }); - expect(resolveMemorySearchSyncConfig(cfg, "main")).toEqual({ + expect(resolveMemorySearchSyncConfig(cfg, "main")).toStrictEqual({ onSessionStart: true, onSearch: true, watch: true, @@ -517,22 +517,23 @@ describe("memory search config", () => { }); }); - it("keeps the fixed embedding batch timeout unset", () => { - const cfg = asConfig({ - memory: { - search: { - provider: "openai", - }, - }, + it("keeps resolved defaults isolated across calls and sync-only consumers", () => { + const cfg = configWithDefaultProvider("openai"); + const resolved = resolveMemorySearchConfig(cfg, "main")!; + const expected = structuredClone(resolved); + expect(resolved.cache).toStrictEqual({ enabled: true, maxEntries: undefined }); - agents: { - defaults: {}, - }, - }); + resolved.chunking.tokens = 1; + resolved.chunking.overlap = 0; + resolved.sync.watch = false; + resolved.sync.sessions.deltaBytes = 0; + resolved.query.hybrid.vectorWeight = 0; + resolved.query.hybrid.mmr.lambda = 0; + resolved.query.hybrid.temporalDecay.halfLifeDays = 1; + resolved.cache.enabled = false; - expect( - resolveMemorySearchSyncConfig(cfg, "main")?.embeddingBatchTimeoutSeconds, - ).toBeUndefined(); + expect(resolveMemorySearchConfig(cfg, "main")).toStrictEqual(expected); + expect(resolveMemorySearchSyncConfig(cfg, "main")).toStrictEqual(expected.sync); }); it("merges defaults and overrides", () => { diff --git a/src/agents/memory-search.ts b/src/agents/memory-search.ts index 0ede5df92560..34d594903e2a 100644 --- a/src/agents/memory-search.ts +++ b/src/agents/memory-search.ts @@ -2,10 +2,6 @@ * Resolves memory-search source, sync, and ranking configuration. */ import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id"; -import { - MAX_TIMER_TIMEOUT_MS, - resolvePositiveTimerTimeoutMs, -} from "@openclaw/normalization-core/number-coercion"; import type { OpenClawConfig, MemorySearchConfig } from "../config/config.js"; import type { SecretInput } from "../config/types.secrets.js"; import { @@ -22,7 +18,7 @@ import { getMemoryEmbeddingProvider } from "../plugins/memory-embedding-provider import { assertSecretOwnerAvailable } from "../secrets/runtime-degraded-state.js"; import { runtimeMemorySecretOwnerId } from "../secrets/runtime-memory-secret-owner.js"; import { resolveOpenClawAgentSqlitePath } from "../state/openclaw-agent-db.paths.js"; -import { clampInt, clampNumber } from "../utils.js"; +import { clampNumber } from "../utils.js"; import { resolveAgentConfig } from "./agent-scope.js"; export type ResolvedMemorySearchConfig = { @@ -137,7 +133,6 @@ const DEFAULT_SOURCES: Array<"memory" | "sessions"> = ["memory"]; const DEFAULT_MEMORY_EMBEDDING_PROVIDER = "openai"; const DEFAULT_REMOTE_BATCH_POLL_INTERVAL_MS = 2_000; const DEFAULT_REMOTE_BATCH_TIMEOUT_MINUTES = 60; -const MAX_REMOTE_BATCH_TIMEOUT_MINUTES = Math.floor(MAX_TIMER_TIMEOUT_MS / 60_000); type ConfiguredMemoryEmbeddingProvider = { defaultModel?: string; @@ -145,26 +140,6 @@ type ConfiguredMemoryEmbeddingProvider = { supportsMultimodalEmbeddings?: (params: { model: string }) => boolean; }; -function resolveRemoteBatchPollIntervalMs( - overrideValue: number | undefined, - defaultValue: number | undefined, -): number { - return resolvePositiveTimerTimeoutMs( - overrideValue ?? defaultValue, - DEFAULT_REMOTE_BATCH_POLL_INTERVAL_MS, - ); -} - -function resolveRemoteBatchTimeoutMinutes( - overrideValue: number | undefined, - defaultValue: number | undefined, -): number { - const value = overrideValue ?? defaultValue; - return typeof value === "number" && Number.isFinite(value) && value > 0 - ? clampInt(value, 1, MAX_REMOTE_BATCH_TIMEOUT_MINUTES) - : DEFAULT_REMOTE_BATCH_TIMEOUT_MINUTES; -} - function normalizeSources( sources: Array<"memory" | "sessions"> | undefined, sessionMemoryEnabled: boolean, @@ -238,8 +213,8 @@ function mergeConfig( enabled: overrideRemote?.batch?.enabled ?? defaultRemote?.batch?.enabled ?? false, wait: true, concurrency: 2, - pollIntervalMs: resolveRemoteBatchPollIntervalMs(undefined, undefined), - timeoutMinutes: resolveRemoteBatchTimeoutMinutes(undefined, undefined), + pollIntervalMs: DEFAULT_REMOTE_BATCH_POLL_INTERVAL_MS, + timeoutMinutes: DEFAULT_REMOTE_BATCH_TIMEOUT_MINUTES, }; const remote = includeRemote ? { @@ -297,7 +272,7 @@ function mergeConfig( tokens: DEFAULT_CHUNK_TOKENS, overlap: DEFAULT_CHUNK_OVERLAP, }; - const sync = resolveSyncConfig(defaults, overrides); + const sync = resolveSyncConfig(); const query = { maxResults: overrides?.query?.maxResults ?? defaults?.query?.maxResults ?? DEFAULT_MAX_RESULTS, minScore: overrides?.query?.minScore ?? defaults?.query?.minScore ?? DEFAULT_MIN_SCORE, @@ -321,25 +296,7 @@ function mergeConfig( maxEntries: DEFAULT_CACHE_MAX_ENTRIES, }; - const overlap = clampNumber(chunking.overlap, 0, Math.max(0, chunking.tokens - 1)); const minScore = clampNumber(query.minScore, 0, 1); - const vectorWeight = clampNumber(hybrid.vectorWeight, 0, 1); - const textWeight = clampNumber(hybrid.textWeight, 0, 1); - const sum = vectorWeight + textWeight; - const normalizedVectorWeight = sum > 0 ? vectorWeight / sum : DEFAULT_HYBRID_VECTOR_WEIGHT; - const normalizedTextWeight = sum > 0 ? textWeight / sum : DEFAULT_HYBRID_TEXT_WEIGHT; - const candidateMultiplier = clampInt(hybrid.candidateMultiplier, 1, 20); - const temporalDecayHalfLifeDays = Math.max( - 1, - Math.floor( - Number.isFinite(hybrid.temporalDecay.halfLifeDays) - ? hybrid.temporalDecay.halfLifeDays - : DEFAULT_TEMPORAL_DECAY_HALF_LIFE_DAYS, - ), - ); - const deltaBytes = clampInt(sync.sessions.deltaBytes, 0, Number.MAX_SAFE_INTEGER); - const deltaMessages = clampInt(sync.sessions.deltaMessages, 0, Number.MAX_SAFE_INTEGER); - const postCompactionForce = sync.sessions.postCompactionForce; return { enabled, rememberAcrossConversations, @@ -360,49 +317,18 @@ function mergeConfig( outputDimensionality, local, store, - chunking: { tokens: Math.max(1, chunking.tokens), overlap }, - sync: { - ...sync, - sessions: { - deltaBytes, - deltaMessages, - postCompactionForce, - }, - }, + chunking, + sync, query: { ...query, minScore, - hybrid: { - enabled: hybrid.enabled, - vectorWeight: normalizedVectorWeight, - textWeight: normalizedTextWeight, - candidateMultiplier, - mmr: { - enabled: hybrid.mmr.enabled, - lambda: Number.isFinite(hybrid.mmr.lambda) - ? Math.max(0, Math.min(1, hybrid.mmr.lambda)) - : DEFAULT_MMR_LAMBDA, - }, - temporalDecay: { - enabled: hybrid.temporalDecay.enabled, - halfLifeDays: temporalDecayHalfLifeDays, - }, - }, - }, - cache: { - enabled: cache.enabled, - maxEntries: - typeof cache.maxEntries === "number" && Number.isFinite(cache.maxEntries) - ? Math.max(1, Math.floor(cache.maxEntries)) - : undefined, + hybrid, }, + cache, }; } -function resolveSyncConfig( - _defaults: MemorySearchConfig | undefined, - _overrides: MemorySearchConfig | undefined, -): ResolvedMemorySearchSyncConfig { +function resolveSyncConfig(): ResolvedMemorySearchSyncConfig { return { onSessionStart: true, onSearch: true, @@ -464,5 +390,5 @@ export function resolveMemorySearchSyncConfig( if (!enabled) { return null; } - return resolveSyncConfig(defaults, overrides); + return resolveSyncConfig(); }