UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

109 lines (108 loc) • 6.16 kB
import { i as executeSqliteQuerySync, o as getNodeSqliteKysely, s as iterateSqliteQuerySync, t as compileSqliteQueryBindings } from "./kysely-sync-DUWzQvCU.mjs"; import { n as decodeMemoryEmbedding, r as encodeMemoryEmbedding } from "./embedding-vector-DA_9H0FL.mjs"; import "./memory-core-host-engine-storage-D6wIwcVO.mjs"; import "./sqlite-worker-runtime-EkcIEvGh.mjs"; //#region extensions/memory-core/src/memory/manager-embedding-cache.ts /** Require a finite, nonempty vector compatible with the active embedding dimensions. */ function isValidMemoryEmbedding(embedding, dimensions) { return Array.isArray(embedding) && embedding.length > 0 && (dimensions === void 0 || embedding.length === dimensions) && embedding.every((coordinate) => typeof coordinate === "number" && Number.isFinite(coordinate)); } function loadMemoryEmbeddingCache(params) { if (params.providerIdentities.length === 0 || params.hashes.length === 0) return /* @__PURE__ */ new Map(); const unresolved = new Set(params.hashes.filter(Boolean)); if (unresolved.size === 0) return /* @__PURE__ */ new Map(); const db = getNodeSqliteKysely(params.db); const out = /* @__PURE__ */ new Map(); const batchSize = 400; for (const identity of params.providerIdentities) { if (unresolved.size === 0) break; const hashes = [...unresolved]; for (let start = 0; start < hashes.length; start += batchSize) { const batch = hashes.slice(start, start + batchSize); const query = db.selectFrom("memory_embedding_cache").select(["hash", "embedding"]).select((eb) => eb.or([eb("dims", "is", null), eb("dims", "=", eb(eb.fn("length", ["embedding"]), "/", eb.lit(8)))]).as("dimensions_match")).where("provider", "=", identity.provider).where("model", "=", identity.model).where("provider_key", "=", identity.providerKey).where("hash", "in", batch); for (const row of iterateSqliteQuerySync(params.db, query)) { const embedding = decodeMemoryEmbedding(row.embedding); out.set(row.hash, row.dimensions_match && isValidMemoryEmbedding(embedding) ? embedding : []); unresolved.delete(row.hash); } } } return out; } function countMemoryEmbeddingCache(database) { const db = getNodeSqliteKysely(database); return executeSqliteQuerySync(database, db.selectFrom("memory_embedding_cache").select((eb) => eb.fn.countAll().as("count"))).rows[0].count; } /** The caller holds the write transaction; another purge may have reduced the cache. */ function pruneMemoryEmbeddingCache(database, maxEntries) { const excess = countMemoryEmbeddingCache(database) - maxEntries; if (excess <= 0) return; deleteOldestMemoryEmbeddingCacheRows(database, Math.min(excess, 100)); } function deleteOldestMemoryEmbeddingCacheRows(database, limit) { const db = getNodeSqliteKysely(database); executeSqliteQuerySync(database, db.deleteFrom("memory_embedding_cache").where("rowid", "in", db.selectFrom("memory_embedding_cache").select("rowid").orderBy("updated_at", "asc").orderBy("rowid", "asc").limit(limit))); } /** Discard ambiguous vector spaces without removing unrelated provider caches or index rows. */ function clearMemoryEmbeddingCacheIdentities(database, identities) { const db = getNodeSqliteKysely(database); for (const identity of identities) executeSqliteQuerySync(database, db.deleteFrom("memory_embedding_cache").where("provider", "=", identity.provider).where("model", "=", identity.model).where("provider_key", "=", identity.providerKey)); } function upsertMemoryEmbeddingCache(params) { const provider = params.provider; const lastRows = /* @__PURE__ */ new Map(); let row = 0; for (const entry of params.entries()) lastRows.set(entry.hash, row++); const uniqueRows = [...lastRows].toSorted((left, right) => left[1] - right[1]); const maxEntries = typeof params.maxEntries === "number" && Number.isFinite(params.maxEntries) && params.maxEntries > 0 ? Math.floor(params.maxEntries) : void 0; const retainedRows = maxEntries === void 0 ? uniqueRows : uniqueRows.slice(-maxEntries); if (retainedRows.length === 0) return; if (maxEntries !== void 0) { const db = getNodeSqliteKysely(params.db); const hashes = retainedRows.map(([hash]) => hash); for (let start = 0; start < hashes.length; start += 400) executeSqliteQuerySync(params.db, db.deleteFrom("memory_embedding_cache").where("provider", "=", provider.id).where("model", "=", provider.model).where("provider_key", "=", params.providerKey).where("hash", "in", hashes.slice(start, start + 400))); const excess = countMemoryEmbeddingCache(params.db) - (maxEntries - hashes.length); if (excess > 0) deleteOldestMemoryEmbeddingCacheRows(params.db, excess); } const now = params.now ?? Date.now(); const { compiled, bind } = compileSqliteQueryBindings((parameter) => getNodeSqliteKysely(params.db).insertInto("memory_embedding_cache").values({ provider: provider.id, model: provider.model, provider_key: params.providerKey, hash: parameter((entry) => entry.hash), embedding: parameter((entry) => encodeMemoryEmbedding(entry.embedding)), dims: parameter((entry) => entry.embedding.length), updated_at: now }).onConflict((conflict) => conflict.columns([ "provider", "model", "provider_key", "hash" ]).doUpdateSet((eb) => ({ embedding: eb.ref("excluded.embedding"), dims: eb.ref("excluded.dims"), updated_at: eb.ref("excluded.updated_at") })))); const statement = params.db.prepare(compiled.sql); statement.setReadBigInts(true); const retained = new Set(retainedRows.map(([, index]) => index)); row = 0; for (const entry of params.entries()) { if (!retained.has(row++)) continue; statement.run(...bind(entry)); } } function collectMemoryCachedEmbeddings(params) { const missing = []; return { embeddings: params.hashes.map((hash, index) => { const hit = hash ? params.cached.get(hash) : void 0; if (hit && hit.length > 0) return hit; missing.push(index); return []; }), missing }; } //#endregion export { loadMemoryEmbeddingCache as a, isValidMemoryEmbedding as i, collectMemoryCachedEmbeddings as n, pruneMemoryEmbeddingCache as o, countMemoryEmbeddingCache as r, upsertMemoryEmbeddingCache as s, clearMemoryEmbeddingCacheIdentities as t };