refactor(memory): remove normalization of fixed search defaults (#130655)

This commit is contained in:
Peter Steinberger
2026-08-26 21:01:21 -07:00
committed by GitHub
parent 8dac217ce9
commit 30e7ecb454
2 changed files with 26 additions and 99 deletions
+16 -15
View File
@@ -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", () => {
+10 -84
View File
@@ -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();
}