diff --git a/mem0-ts/src/oss/src/config/manager.ts b/mem0-ts/src/oss/src/config/manager.ts index 27903e7072..b002e39631 100644 --- a/mem0-ts/src/oss/src/config/manager.ts +++ b/mem0-ts/src/oss/src/config/manager.ts @@ -155,6 +155,7 @@ export class ConfigManager { })(), disableHistory: userConfig.disableHistory || DEFAULT_MEMORY_CONFIG.disableHistory, + parallelEntityBoost: userConfig.parallelEntityBoost === true, }; // Validate the merged config diff --git a/mem0-ts/src/oss/src/memory/index.ts b/mem0-ts/src/oss/src/memory/index.ts index f2856c4939..217aa41855 100644 --- a/mem0-ts/src/oss/src/memory/index.ts +++ b/mem0-ts/src/oss/src/memory/index.ts @@ -1164,7 +1164,13 @@ export class Memory { if (deduped.length > 0) { const entityStore = await this.getEntityStore(); - for (const entity of deduped) { + // Per-entity worker. Writes to entityBoosts via Math.max, which is + // order-independent under interleaved single-threaded JS writes, + // so this is safe to run sequentially or concurrently. + const processEntity = async (entity: { + type: string; + text: string; + }): Promise => { try { const entityEmbedding = await this.embedder.embed(entity.text); const matches = await entityStore.search( @@ -1201,6 +1207,21 @@ export class Memory { } catch (e) { // Individual entity boost failed — continue } + }; + + if (this.config.parallelEntityBoost) { + // Opt-in: fire entity embeds + lookups concurrently. For remote + // embedders (e.g. ollama over network) this turns N+1 sequential + // RTTs into ~1 RTT, giving 2-4x recall speedup. Backend must + // handle concurrent embed requests (multi-slot ollama, managed + // embed APIs, etc.). + await Promise.all(deduped.map(processEntity)); + } else { + // Default: preserve prior sequential behavior to avoid surprising + // users on rate-limited or single-slot embedder backends. + for (const entity of deduped) { + await processEntity(entity); + } } } } catch (e) { diff --git a/mem0-ts/src/oss/src/types/index.ts b/mem0-ts/src/oss/src/types/index.ts index fd5ec7188f..de358e80c8 100644 --- a/mem0-ts/src/oss/src/types/index.ts +++ b/mem0-ts/src/oss/src/types/index.ts @@ -69,6 +69,14 @@ export interface MemoryConfig { disableHistory?: boolean; historyDbPath?: string; customInstructions?: string; + /** + * When true, run the entity-boost embed+search loop in Memory.search() + * concurrently via Promise.all instead of sequential await. Speeds up + * recall by 2-4x with remote embedders. Default: false (preserves prior + * behavior). Safe to enable when the embedder backend handles concurrent + * requests well (multi-slot ollama, managed embed APIs, batched backends). + */ + parallelEntityBoost?: boolean; } export interface MemoryItem { @@ -142,4 +150,5 @@ export const MemoryConfigSchema = z.object({ }) .optional(), disableHistory: z.boolean().optional(), + parallelEntityBoost: z.boolean().optional(), });