diff --git a/CHANGELOG.md b/CHANGELOG.md index 905b967f9d7..8061c2a2467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Docs: https://docs.openclaw.ai - Cron/context engine: run isolated cron jobs under run-scoped context-engine session keys so prior runs of the same job are not inherited unless the job is explicitly session-bound. (#72292) Thanks @jalehman. - Control UI: localize command palette labels, categories, skill shortcuts, footer hints, and connect-command copy labels while preserving localized command palette search matching. (#61130, #61119) Thanks @rubensfox20. - Plugins/memory-lancedb: request float embedding responses from OpenAI-compatible servers so local providers that default SDK requests to base64 no longer return dimension-mismatched LanceDB vectors while preserving configured dimensions. Fixes #45982. (#59048, #46069, #45986) Thanks @deep-introspection, @xiaokhkh, @caicongyang, and @thiswind. +- Plugins/memory-core: respect configured memory-search embedding concurrency during non-batch indexing so local Ollama embedding backends can serialize indexing instead of flooding the server. Fixes #66822. (#66931) Thanks @oliviareid-svg and @LyraInTheFlesh. ## 2026.4.26 diff --git a/extensions/memory-core/src/memory/manager-embedding-ops.ts b/extensions/memory-core/src/memory/manager-embedding-ops.ts index f49621dca8b..3382dab930f 100644 --- a/extensions/memory-core/src/memory/manager-embedding-ops.ts +++ b/extensions/memory-core/src/memory/manager-embedding-ops.ts @@ -87,6 +87,15 @@ export function resolveEmbeddingTimeoutMs(params: { : EMBEDDING_BATCH_TIMEOUT_REMOTE_MS; } +export function resolveMemoryIndexConcurrency(params: { + batch: { enabled: boolean; concurrency: number }; + configuredConcurrency?: number; +}): number { + return params.configuredConcurrency != null || params.batch.enabled + ? params.batch.concurrency + : EMBEDDING_INDEX_CONCURRENCY; +} + export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps { protected abstract batchFailureCount: number; protected abstract batchFailureLastError?: string; @@ -498,7 +507,10 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps { } protected getIndexConcurrency(): number { - return this.batch.enabled ? this.batch.concurrency : EMBEDDING_INDEX_CONCURRENCY; + return resolveMemoryIndexConcurrency({ + batch: this.batch, + configuredConcurrency: this.settings.remote?.batch?.concurrency, + }); } private clearIndexedFileData(pathname: string, source: MemorySource): void { diff --git a/extensions/memory-core/src/memory/manager-embedding-timeout.test.ts b/extensions/memory-core/src/memory/manager-embedding-timeout.test.ts index ebdd72160d8..bf67130f0c1 100644 --- a/extensions/memory-core/src/memory/manager-embedding-timeout.test.ts +++ b/extensions/memory-core/src/memory/manager-embedding-timeout.test.ts @@ -1,5 +1,8 @@ import { describe, expect, it } from "vitest"; -import { resolveEmbeddingTimeoutMs } from "./manager-embedding-ops.js"; +import { + resolveEmbeddingTimeoutMs, + resolveMemoryIndexConcurrency, +} from "./manager-embedding-ops.js"; describe("memory embedding timeout resolution", () => { it("uses hosted defaults for inline embedding calls", () => { @@ -33,3 +36,30 @@ describe("memory embedding timeout resolution", () => { ).toBe(45_000); }); }); + +describe("memory index concurrency resolution", () => { + it("uses the default index concurrency when batch mode is disabled and unconfigured", () => { + expect( + resolveMemoryIndexConcurrency({ + batch: { enabled: false, concurrency: 2 }, + }), + ).toBe(4); + }); + + it("respects configured concurrency even when batch mode is disabled", () => { + expect( + resolveMemoryIndexConcurrency({ + batch: { enabled: false, concurrency: 1 }, + configuredConcurrency: 1, + }), + ).toBe(1); + }); + + it("uses resolved batch concurrency when batch mode is enabled", () => { + expect( + resolveMemoryIndexConcurrency({ + batch: { enabled: true, concurrency: 3 }, + }), + ).toBe(3); + }); +});