openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
194 lines (193 loc) • 7.97 kB
JavaScript
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 };