UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

194 lines (193 loc) • 7.97 kB
import { c as supportsNodeSqliteExtensionLoading, i as resolveExistingSqliteFileUri, t as openNodeSqliteDatabase } from "./node-sqlite-DWTcT2ek.mjs"; import { a as runSqliteImmediateTransactionSync, t as assertTransactionUsable } from "./sqlite-transaction-DlnLAQiX.mjs"; import { i as requestSqliteWorkerOperationAdmission } from "./sqlite-worker-operation-admission-DqFz0WIG.mjs"; import { n as loadSqliteVecExtensionFromPath } from "./sqlite-vec-B4b2b9F7.mjs"; import "./memory-core-host-engine-schema-Bv75zkix.mjs"; import "./sqlite-worker-runtime-CSSFY-RJ.mjs"; import { t as MemorySourceIndexKernel } from "./manager-source-index-kernel-HZ7Yp_Kl.mjs"; import { n as hasMemorySessionTombstone } from "./memory-session-tombstones-C1mWWpWO.mjs"; import { n as publishMemoryDatabaseTables, r as readMemoryDatabaseRevision } from "./manager-db-kernel-B67mW9CG.mjs"; import { t as assertMemoryShadowIdentity } from "./manager-shadow-task-DGuJMed1.mjs"; //#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 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}`); } }; 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 === "stage.start") { if (staged) throw new Error("Memory publication input already belongs to another operation"); staged = { ...command.input, 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; } 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 transact((hooks) => runSqliteImmediateTransactionSync(db, () => { hooks.onBegin(); return new MemorySourceIndexKernel(db, command.input.state).deleteIfCurrent(command.input); }, { withCommit: hooks.withCommit })); if (!staged || 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 = transact((hooks) => runSqliteImmediateTransactionSync(db, () => { hooks.onBegin(); 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) }; }, { withCommit: hooks.withCommit })); if (outcome.ok) try { discard(); } catch (error) { return { ok: false, error: failure(error), entered: true, committed: true }; } return 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) { 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 JSON.parse(parts.join("")); parts = []; row = Number(fragment.row); } parts.push(String(fragment.json)); } if (parts.length) yield JSON.parse(parts.join("")); } //#endregion export { openExistingSqliteWorkerBackend as n, bindSqliteWorkerBackend as t };