UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

411 lines (410 loc) • 17.3 kB
import { a as getNodeSqliteKysely, i as executeSqliteQueryTakeFirstSync, r as executeSqliteQuerySync, t as compileSqliteQueryBindings } from "./kysely-sync-K7ftY-g4.mjs"; import { r as resolveExistingSqliteFileUri, s as supportsNodeSqliteExtensionLoading, t as openNodeSqliteDatabase } from "./node-sqlite-XIcwmOrl.mjs"; import { a as runSqliteImmediateTransactionSync, t as assertTransactionUsable } from "./sqlite-transaction-DsZ3X6nD.mjs"; import { u as MEMORY_INDEX_VECTOR_TABLE } from "./memory-schema-BA04oCjG.mjs"; import { r as encodeMemoryEmbedding } from "./embedding-vector-DA_9H0FL.mjs"; import { i as requestSqliteWorkerOperationAdmission } from "./sqlite-worker-operation-admission-cNGSH5v0.mjs"; import { n as loadSqliteVecExtensionFromPath } from "./sqlite-vec-BcbJNyja.mjs"; import { t as vectorToBlob } from "./vector-blob-T_j5xTNO.mjs"; import { t as hashText } from "./hash-BOTtT1fO.mjs"; import "./memory-core-host-engine-schema-C2UMfTcl.mjs"; import { n as markMemoryVectorRebuildRequired, r as memoryTableExists } from "./manager-vector-rebuild-state-DWrs_Mbx.mjs"; import "./memory-core-host-engine-indexing-JxQYGRDs.mjs"; import "./sqlite-worker-runtime-BFi6Nryt.mjs"; import { n as hasMemorySessionTombstone } from "./memory-session-tombstones-Boi0AhzJ.mjs"; import { n as publishMemoryDatabaseTables, r as readMemoryDatabaseRevision } from "./manager-db-kernel-P1lEjy52.mjs"; import { a as countMemoryEmbeddingCache, c as pruneMemoryEmbeddingCache, l as upsertMemoryEmbeddingCache, r as clearMemoryEmbeddingCacheIdentities, s as loadMemoryEmbeddingCache, t as assertMemoryShadowIdentity } from "./manager-shadow-task-D6NGNpD7.mjs"; //#region extensions/memory-core/src/memory/manager-chunk-writer.ts function createMemoryChunkWriter(database, context) { const db = getNodeSqliteKysely(database); const chunkWrite = compileSqliteQueryBindings((parameter) => db.insertInto("memory_index_chunks").values({ id: parameter((row) => row.id), path: context.path, source: context.source, start_line: parameter((row) => row.chunk.startLine), end_line: parameter((row) => row.chunk.endLine), hash: parameter((row) => row.chunk.hash), model: context.model, text: parameter((row) => row.chunk.text), embedding: parameter((row) => encodeMemoryEmbedding(row.embedding)), updated_at: context.now }).onConflict((conflict) => conflict.column("id").doUpdateSet((eb) => ({ hash: eb.ref("excluded.hash"), model: eb.ref("excluded.model"), text: eb.ref("excluded.text"), embedding: eb.ref("excluded.embedding"), updated_at: eb.ref("excluded.updated_at") })))); const recallWrite = compileSqliteQueryBindings((parameter) => db.insertInto("memory_index_chunk_recall_metadata").values({ chunk_id: parameter((row) => row.id), importance: parameter((row) => row.chunk.importance), triggers: parameter((row) => row.chunk.triggers), project_key: parameter((row) => row.chunk.projectKey) }).onConflict((conflict) => conflict.column("chunk_id").doUpdateSet((eb) => ({ importance: eb.ref("excluded.importance"), triggers: eb.ref("excluded.triggers"), project_key: eb.ref("excluded.project_key") })))); const provenanceWrite = compileSqliteQueryBindings((parameter) => db.insertInto("memory_index_chunk_provenance").values({ chunk_id: parameter((row) => row.id), origin_class: parameter((row) => row.provenance.originClass), session_kind: parameter((row) => row.provenance.sessionKind), observed_at: parameter((row) => row.provenance.observedAt), supersedes_key: parameter((row) => row.provenance.supersedesKey ?? null) }).onConflict((conflict) => conflict.column("chunk_id").doUpdateSet((eb) => ({ origin_class: eb.ref("excluded.origin_class"), session_kind: eb.ref("excluded.session_kind"), observed_at: eb.ref("excluded.observed_at"), supersedes_key: eb.ref("excluded.supersedes_key") })))); let chunkStatement; let recallStatement; let provenanceStatement; return (id, chunk, embedding) => { const row = { id, chunk, embedding }; (chunkStatement ??= database.prepare(chunkWrite.compiled.sql)).run(...chunkWrite.bind(row)); (recallStatement ??= database.prepare(recallWrite.compiled.sql)).run(...recallWrite.bind(row)); const provenance = chunk.provenance ?? { originClass: "untrusted", sessionKind: "unknown", observedAt: context.now }; (provenanceStatement ??= database.prepare(provenanceWrite.compiled.sql)).run(...provenanceWrite.bind({ id, provenance })); }; } //#endregion //#region extensions/memory-core/src/memory/manager-vector-write.ts function createMemoryVectorWriter(db, tableName = "memory_index_chunks_vec") { let deleteStatement; let insertStatement; return (id, embedding) => { try { (deleteStatement ??= db.prepare(`DELETE FROM ${tableName} WHERE id = ?`)).run(id); } catch {} (insertStatement ??= db.prepare(`INSERT INTO ${tableName} (id, embedding) VALUES (?, ?)`)).run(id, vectorToBlob(embedding)); }; } //#endregion //#region extensions/memory-core/src/memory/manager-source-index-kernel.ts const MAX_VECTOR_POINT_DELETES = 32; function readMemorySourceHash(db, source, path) { return executeSqliteQueryTakeFirstSync(db, getNodeSqliteKysely(db).selectFrom("memory_index_sources").select("hash").where("path", "=", path).where("source", "=", source))?.hash; } var MemorySourceIndexKernel = class { constructor(database, state) { this.database = database; this.state = state; } replaceRows(params, rows) { const { entry, source, model, now, vectorReady } = params; this.clear(entry.path, source); let writeChunk; let writeVector; let hasEmbeddings = false; for (const { chunk, embedding } of rows) { hasEmbeddings ||= embedding.length > 0; const id = hashText(`${source}:${entry.path}:${chunk.startLine}:${chunk.endLine}:${chunk.hash}:${model}`); writeChunk ??= createMemoryChunkWriter(this.database, { path: entry.path, source, model, now }); writeChunk(id, chunk, embedding); if (vectorReady && embedding.length > 0) { writeVector ??= createMemoryVectorWriter(this.database, MEMORY_INDEX_VECTOR_TABLE); writeVector(id, embedding); } } const db = getNodeSqliteKysely(this.database); executeSqliteQuerySync(this.database, db.insertInto("memory_index_sources").values({ path: entry.path, source, hash: entry.hash, mtime: entry.mtimeMs, size: entry.size }).onConflict((conflict) => conflict.columns(["path", "source"]).doUpdateSet((eb) => ({ hash: eb.ref("excluded.hash"), mtime: eb.ref("excluded.mtime"), size: eb.ref("excluded.size") })))); if (!vectorReady && hasEmbeddings) markMemoryVectorRebuildRequired(this.database); } deleteIfCurrent(params) { if (readMemorySourceHash(this.database, params.source, params.path) !== params.expectedHash) return false; this.clear(params.path, params.source); executeSqliteQuerySync(this.database, getNodeSqliteKysely(this.database).deleteFrom("memory_index_sources").where("path", "=", params.path).where("source", "=", params.source)); return true; } clear(pathname, source) { if (memoryTableExists(this.database, "memory_index_chunks_vec")) { if (!this.state.vector.enabled || this.state.vector.available !== true) markMemoryVectorRebuildRequired(this.database); else try { runSqliteImmediateTransactionSync(this.database, () => { const rows = executeSqliteQuerySync(this.database, getNodeSqliteKysely(this.database).selectFrom("memory_index_chunks").select("id").where("path", "=", pathname).where("source", "=", source).limit(33)).rows; if (rows.length > MAX_VECTOR_POINT_DELETES) { this.database.prepare(`DELETE FROM ${MEMORY_INDEX_VECTOR_TABLE} WHERE id IN (SELECT id FROM memory_index_chunks WHERE path = ? AND source = ?)`).run(pathname, source); return; } const removeVector = this.database.prepare(`DELETE FROM ${MEMORY_INDEX_VECTOR_TABLE} WHERE id = ?`); for (const { id } of rows) removeVector.run(id); }); } catch { markMemoryVectorRebuildRequired(this.database); } } executeSqliteQuerySync(this.database, getNodeSqliteKysely(this.database).deleteFrom("memory_index_chunks").where("path", "=", pathname).where("source", "=", source)); } }; //#endregion //#region extensions/memory-core/src/memory/manager-publication.worker.ts function failure(error) { return { name: error instanceof Error ? error.name : "Error", message: error instanceof Error ? error.message : String(error), ...error && typeof error === "object" && "code" in error && typeof error.code === "string" ? { code: error.code } : {}, ...error && typeof error === "object" && "errcode" in error && typeof error.errcode === "number" ? { errcode: error.errcode } : {} }; } function openExistingSqliteWorkerBackend(input, context) { const assertPath = () => assertMemoryShadowIdentity(context.databasePath, input.fileIdentity); assertPath(); const db = openNodeSqliteDatabase(resolveExistingSqliteFileUri(context.databasePath), { allowExtension: !process.permission && supportsNodeSqliteExtensionLoading() }); return createPublicationBackend(input, context.databasePath, db, true, (stage) => requestSqliteWorkerOperationAdmission({ stage, facts: void 0 })); } /** Agent publication borrows its executor connection; only private shadows open their own. */ function bindSqliteWorkerBackend(input, context) { return createPublicationBackend(input, context.databasePath, context.database, false, (stage) => context.admit(stage)); } function createPublicationBackend(input, databasePath, db, ownsConnection, admit) { const assertPath = () => assertMemoryShadowIdentity(databasePath, input.fileIdentity); let staged; let loadedExtension; try { assertPath(); for (const [name, value] of Object.entries(input.pragmas)) { if (!Number.isSafeInteger(value)) throw new Error("Invalid memory publication connection policy"); if (ownsConnection) db.exec(`PRAGMA ${name} = ${value}`); else { const row = db.prepare(`PRAGMA ${name}`).get(); if (!row || Number(Object.values(row)[0]) !== value) throw new Error(`Memory publication differs from its canonical connection policy: ${name}`); } } if (ownsConnection) db.exec("PRAGMA temp_store = FILE"); db.exec("CREATE TEMP TABLE memory_publication_input (row INTEGER NOT NULL, part INTEGER NOT NULL, json TEXT NOT NULL, PRIMARY KEY (row, part)) WITHOUT ROWID"); const insert = db.prepare("INSERT INTO temp.memory_publication_input (row, part, json) VALUES (?, ?, ?)"); const discard = () => { db.exec("DELETE FROM temp.memory_publication_input"); staged = void 0; }; const finish = (outcome) => { if (outcome.ok) try { discard(); } catch (error) { return { ok: false, error: failure(error), entered: true, committed: true }; } return outcome; }; const transact = (run) => { let entered = false; let committed = false; try { assertPath(); db.exec("PRAGMA busy_timeout = 0"); return { ok: true, value: run({ onBegin: () => { entered = true; db.exec(`PRAGMA busy_timeout = ${input.pragmas.busy_timeout}`); assertPath(); admit("transaction"); }, withCommit: (commit) => { assertPath(); admit("commit"); commit(); committed = true; } }) }; } catch (error) { return { ok: false, error: failure(error), entered, committed }; } finally { if (db.isOpen) db.exec(`PRAGMA busy_timeout = ${input.pragmas.busy_timeout}`); } }; const write = (run) => transact((hooks) => runSqliteImmediateTransactionSync(db, () => { hooks.onBegin(); return run(); }, { withCommit: hooks.withCommit })); return { assertSettled() { assertTransactionUsable(db); if (!db.isOpen || db.isTransaction) throw new Error("Memory publication left an unsettled native connection"); }, execute(command) { assertPath(); if (command.type === "source.hash") return readMemorySourceHash(db, command.input.source, command.input.path); if (command.type === "cache.read") return loadMemoryEmbeddingCache({ ...command.input, db }); if (command.type === "stage.start" || command.type === "cache.stage.start") { if (staged) throw new Error("Memory publication input already belongs to another operation"); staged = command.type === "stage.start" ? { ...command.input, kind: "source", row: 0, part: 0 } : { ...command.input, kind: "cache", row: 0, part: 0 }; return; } if (command.type === "stage.discard") { if (staged?.operation === command.input.operation) discard(); return; } if (command.type === "stage.append") { if (!staged || staged.operation !== command.input.operation) throw new Error("Memory publication input owner changed"); for (const fragment of command.input.fragments) { if (fragment.row !== staged.row || fragment.part !== staged.part || staged.row >= staged.rows) throw new Error("Memory publication input is incomplete or out of order"); insert.run(fragment.row, fragment.part, fragment.json); if (fragment.last) { staged.row++; staged.part = 0; } else staged.part++; } return; } if (command.type === "cache.prune") { if (countMemoryEmbeddingCache(db) <= command.input.maxEntries) return { ok: true, value: false }; return write(() => { pruneMemoryEmbeddingCache(db, command.input.maxEntries); return true; }); } if (command.type === "cache.clear") return write(() => { if (readMemoryDatabaseRevision(db) !== command.input.expectedRevision) return false; clearMemoryEmbeddingCacheIdentities(db, command.input.identities); return true; }); if (command.type === "cache.write") { if (!staged || staged.kind !== "cache" || staged.operation !== command.input.operation || staged.row !== staged.rows || staged.part !== 0) throw new Error("Memory cache input was not sealed"); const header = staged.header; return finish(write(() => { if (readMemoryDatabaseRevision(db) !== command.input.expectedRevision) return false; const eligible = /* @__PURE__ */ new Map(); function* entries() { for (const json of readStagedJson(db)) { const entry = JSON.parse(json); if (entry.sessionId) { let current = eligible.get(entry.sessionId); if (current === void 0) { current = !hasMemorySessionTombstone(db, header.agentId, entry.sessionId); eligible.set(entry.sessionId, current); } if (!current) continue; } yield entry; } } upsertMemoryEmbeddingCache({ ...header, db, enabled: true, entries }); return true; })); } const extensionPath = command.input.state.extensionPath; if (extensionPath && extensionPath !== loadedExtension) { loadSqliteVecExtensionFromPath(db, extensionPath); assertPath(); loadedExtension = extensionPath; } if (command.type === "database.publish") { const publication = command.input; return transact((hooks) => { assertMemoryShadowIdentity(publication.sourcePath, publication.sourceIdentity); publishMemoryDatabaseTables({ ...publication, targetDb: db, onBegin: () => { hooks.onBegin(); assertMemoryShadowIdentity(publication.sourcePath, publication.sourceIdentity); }, withCommit: hooks.withCommit }); }); } if (command.type === "source.delete") return write(() => new MemorySourceIndexKernel(db, command.input.state).deleteIfCurrent(command.input)); if (!staged || staged.kind !== "source" || staged.operation !== command.input.operation || staged.row !== staged.rows || staged.part !== 0) throw new Error("Memory publication input was not sealed"); const header = staged.header; const outcome = write(() => { if (header.source === "sessions" && hasMemorySessionTombstone(db, header.agentId, header.sessionId)) throw new Error("A session was forgotten while memory indexing was running; retry the memory index."); const beforeRevision = readMemoryDatabaseRevision(db); new MemorySourceIndexKernel(db, command.input.state).replaceRows(header, readStagedRows(db)); return { beforeRevision, databaseRevision: readMemoryDatabaseRevision(db) }; }); return finish(outcome); }, close() { if (ownsConnection) db.close(); else db.exec("DROP TABLE temp.memory_publication_input"); } }; } catch (error) { if (ownsConnection) db.close(); throw error; } } function* readStagedRows(db) { for (const json of readStagedJson(db)) yield JSON.parse(json); } function* readStagedJson(db) { let parts = []; let row = 0; for (const fragment of db.prepare("SELECT row, json FROM temp.memory_publication_input ORDER BY row, part").iterate()) { if (fragment.row !== row) { yield parts.join(""); parts = []; row = Number(fragment.row); } parts.push(String(fragment.json)); } if (parts.length) yield parts.join(""); } //#endregion export { openExistingSqliteWorkerBackend as n, bindSqliteWorkerBackend as t };