Skip to content

Commit fbf574a

Browse files
committed
perf(memory): skip FTS-only plugin discovery
1 parent aa1929c commit fbf574a

3 files changed

Lines changed: 47 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
2121

2222
### Fixes
2323

24+
- **FTS-only memory startup:** skip plugin capability discovery when `memorySearch.provider` is explicitly `none`, avoiding an unnecessary cold-start scan.
2425
- **Control UI agent model labels:** show each selected agent's effective model in the Default picker option instead of the global model. (#100719, #77690, #77440) Thanks @hyspacex.
2526
- **Control UI inbound image previews:** render canonical inbound media references through the authenticated ticket route after chat-history reloads. (#100725, #90172, #89591) Thanks @sweetcornna.
2627
- **Small-context compaction:** cap the effective reserve against the known model context window so small local models do not enter compaction from the first token. (#100621) Thanks @vincentkoc.

src/agents/memory-search.test.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
1616
import { resolveOpenClawAgentSqlitePath } from "../state/openclaw-agent-db.paths.js";
1717
import { resolveMemorySearchConfig, resolveMemorySearchSyncConfig } from "./memory-search.js";
1818

19-
const asConfig = (cfg: OpenClawConfig): OpenClawConfig => cfg;
19+
const asConfig = (cfg: OpenClawConfig): OpenClawConfig => ({
20+
...cfg,
21+
// Provider registries are supplied explicitly below; plugin loading belongs
22+
// to its integration tests and would turn these pure config cases into cold scans.
23+
plugins: cfg.plugins ?? { enabled: false },
24+
});
2025
let registeredEmbeddingProvidersSnapshot: RegisteredEmbeddingProvider[];
2126

2227
function registerBaseMemoryEmbeddingProviders(options?: { includeGemini?: boolean }): void {
@@ -254,9 +259,37 @@ describe("memory search config", () => {
254259
});
255260

256261
it("resolves explicit provider-none", () => {
257-
const resolved = resolveMemorySearchConfig(configWithDefaultProvider("none"), "main");
262+
const resolved = resolveMemorySearchConfig(
263+
asConfig({
264+
plugins: { enabled: true },
265+
agents: {
266+
defaults: { memorySearch: { provider: "none", fallback: "deepinfra" } },
267+
},
268+
}),
269+
"main",
270+
);
271+
272+
expect(resolved?.provider).toBe("none");
273+
});
274+
275+
it("skips multimodal provider discovery for provider-none", () => {
276+
const resolved = resolveMemorySearchConfig(
277+
asConfig({
278+
plugins: { enabled: true },
279+
agents: {
280+
defaults: {
281+
memorySearch: {
282+
provider: "none",
283+
multimodal: { enabled: true, modalities: ["image"] },
284+
},
285+
},
286+
},
287+
}),
288+
"main",
289+
);
258290

259291
expect(resolved?.provider).toBe("none");
292+
expect(resolved?.multimodal.modalities).toEqual(["image"]);
260293
});
261294

262295
it("resolves custom provider ids through their configured api owner", () => {

src/agents/memory-search.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ function getConfiguredMemoryEmbeddingProvider(
185185
providerId: string,
186186
cfg: OpenClawConfig,
187187
): ConfiguredMemoryEmbeddingProvider | undefined {
188+
// `none` is the built-in FTS-only sentinel, never a plugin capability.
189+
// Avoid cold plugin discovery when semantic memory is intentionally disabled.
190+
if (normalizeProviderId(providerId) === "none") {
191+
return undefined;
192+
}
188193
const directAdapter = getMemoryEmbeddingProvider(providerId);
189194
if (directAdapter) {
190195
return directAdapter;
@@ -225,7 +230,7 @@ function mergeConfig(
225230
const overrideRemote = overrides?.remote;
226231
const fallback = overrides?.fallback ?? defaults?.fallback ?? "none";
227232
const fallbackAdapter =
228-
fallback && fallback !== "none"
233+
normalizeProviderId(provider) !== "none" && fallback && fallback !== "none"
229234
? getConfiguredMemoryEmbeddingProvider(fallback, cfg)
230235
: undefined;
231236
const hasRemoteConfig = Boolean(
@@ -476,11 +481,15 @@ export function resolveMemorySearchConfig(
476481
if (!resolved.enabled) {
477482
return null;
478483
}
484+
const isFtsOnly = normalizeProviderId(resolved.provider) === "none";
479485
const multimodalActive = isMemoryMultimodalEnabled(resolved.multimodal);
480-
const multimodalProvider = getConfiguredMemoryEmbeddingProvider(resolved.provider, cfg);
486+
const multimodalProvider = isFtsOnly
487+
? undefined
488+
: getConfiguredMemoryEmbeddingProvider(resolved.provider, cfg);
481489
// Custom provider ids can map to a memory adapter through models.providers.<id>.api.
482490
// Keep multimodal validation on that config-aware adapter, not the raw id.
483491
if (
492+
!isFtsOnly &&
484493
multimodalActive &&
485494
((multimodalProvider &&
486495
!(multimodalProvider.supportsMultimodalEmbeddings?.({ model: resolved.model }) ?? false)) ||

0 commit comments

Comments
 (0)