fix(memory): sync new memories into pgvector
Memind CI / Test, build, and release guards (push) Successful in 2m31s

This commit is contained in:
john
2026-07-21 23:27:15 +08:00
parent 6f4a3b53d0
commit c2e2209344
8 changed files with 425 additions and 57 deletions
+42 -4
View File
@@ -12,7 +12,10 @@ import {
import { createMem0HttpClient, createMem0MemoryBackend } from './memory-v2-mem0.mjs';
import { createNeo4jHttpClient, createNeo4jMemoryBackend } from './memory-v2-neo4j.mjs';
import { createPgvectorMemoryBackend } from './memory-v2-pgvector.mjs';
import { backfillLegacyMemoriesToPgvector } from './memory-v2-pgvector-backfill.mjs';
import {
backfillLegacyMemoriesToPgvector,
syncLegacyUserMemoriesToPgvector,
} from './memory-v2-pgvector-backfill.mjs';
import { createQdrantHttpClient, createQdrantMemoryBackend } from './memory-v2-qdrant.mjs';
import { createRedisStreamsClient, createRedisStreamsMemoryBackend } from './memory-v2-redis-streams.mjs';
import { createWeaviateHttpClient, createWeaviateMemoryBackend } from './memory-v2-weaviate.mjs';
@@ -464,8 +467,26 @@ export async function createMemoryV2Runtime({
let pgBackfillBusy = false;
let pgBackfillCursor = { updatedAt: 0, id: '' };
async function syncPgvectorFromLegacy() {
async function syncPgvectorFromLegacy({ userId = null, sessionId = null } = {}) {
if (!pgBackfillEnabled || !pgPoolRef || !pgEmbedQuery || !mysqlPool?.query) return;
if (userId) {
try {
await syncLegacyUserMemoriesToPgvector({
mysqlPool,
pgPool: pgPoolRef,
embedMemory: (item) => pgEmbedQuery(item.text, item),
tableName: env?.MEMORY_PGVECTOR_TABLE,
userId,
sessionId,
limit: Math.max(1, Number(env?.MEMORY_PGVECTOR_SYNC_USER_LIMIT ?? 50) || 50),
});
} catch (err) {
logger?.warn?.(
`[memory-v2] pgvector user sync skipped: ${err instanceof Error ? err.message : err}`,
);
}
return;
}
if (pgBackfillBusy) return;
pgBackfillBusy = true;
try {
@@ -493,12 +514,29 @@ export async function createMemoryV2Runtime({
}
}
const originalLifecyclePromote = lifecycle.promote.bind(lifecycle);
lifecycle.promote = async (input = {}) => {
const result = await originalLifecyclePromote(input);
if (Number(result?.promoted ?? 0) > 0) {
const promotedUserIds = Array.isArray(result?.promotedUserIds)
? result.promotedUserIds
: input?.userId ? [input.userId] : [];
for (const userId of promotedUserIds) {
await syncPgvectorFromLegacy({ userId });
}
}
return result;
};
function wrapMemorySideEffect(methodName) {
const original = memory[methodName].bind(memory);
memory[methodName] = async (input = {}) => {
const result = await original(input);
if ((result?.memories ?? 0) > 0 || (result?.analyzed ?? 0) > 0) {
void syncPgvectorFromLegacy();
if (input?.userId || (result?.memories ?? 0) > 0 || (result?.analyzed ?? 0) > 0) {
await syncPgvectorFromLegacy({
userId: input?.userId ?? null,
sessionId: input?.sessionId ?? null,
});
}
return result;
};