UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

867 lines (866 loc) • 39.5 kB
import "../src-BirUqOZp.mjs"; import { t as expectDefined } from "../expect-lbe3Hgrh.mjs"; import { c as isRecord } from "../record-coerce-TIsquoVR.mjs"; import { s as sqliteReaderDatabasePathKey } from "../sqlite-reader-lifecycle-CF8Y2ajA.mjs"; import { d as readDatabasePathIdentitySync, r as assertExistingDatabaseIdentity, s as normalizeDatabasePath } from "../sqlite-worker-identity-BRNRpRyc.mjs"; import { a as createSqliteLifecycleAggregateError, s as throwSqliteLifecycleErrors } from "../sqlite-lifecycle-errors-DuOygjcn.mjs"; import { t as createSubsystemLogger } from "../subsystem-4NzR43uz.mjs"; import { t as assertTransactionUsable } from "../sqlite-transaction-DBRLvCDM.mjs"; import { h as onSqliteWalCheckpoint } from "../sqlite-wal-DfKCrDTQ.mjs"; import { a as classifySqliteFtsIntegrityFindings, c as readSqliteIntegrityFindings } from "../sqlite-integrity-D3yHPOet.mjs"; import { a as readOpenClawAgentDatabaseIdentity } from "../openclaw-agent-db-identity-BlmER9-X.mjs"; import { b as withAgentCreationClaimWitness } from "../openclaw-agent-db-resources-Cm-sH7kg.mjs"; import { c as getOpenClawAgentDatabaseValidation } from "../openclaw-agent-db-validation-cache-CHrtutWN.mjs"; import { i as isIncognitoOpenClawAgentSqlitePath } from "../openclaw-agent-db.paths-BbmZlEP5.mjs"; import { a as SQLITE_WORKER_PREPARE_ADMITTED, i as SQLITE_WORKER_OPERATION_CLEANUP, t as SQLITE_WORKER_CLOSE_RECEIPT } from "../sqlite-worker-contract-C51cJHzg.mjs"; import { d as withSqliteWorkerOperationAdmission, i as deferSqliteWorkerCommitReceipt, s as requestSqliteWorkerOperationAdmission, t as SqliteWorkerOpenRefusedError, u as takeSqliteWorkerOperationAdmissionAttachment } from "../sqlite-worker-operation-admission-C5lBzzTk.mjs"; import { b as requireOpenClawStateDatabaseIdentity, x as retainOpenClawStateDatabase } from "../openclaw-state-db-cache-CmYLFRSt.mjs"; import { T as withAgentDeletionWorkerDatabaseCleanup } from "../agent-deletion-journal-DkfGlzu8.mjs"; import { g as repairDoctorSqliteIndexCorruption, l as runOpenClawStateWriteTransaction, r as openOpenClawStateDatabase } from "../openclaw-state-db-DJZ7EKoI.mjs"; import { a as readAgentDeletionJournalStatusInDatabase } from "../agent-deletion-journal.read-BRl4UyPn.mjs"; import { c as runOpenClawAgentWriteTransaction, i as getOpenClawAgentDatabaseIfOpen, o as openOpenClawAgentDatabase } from "../openclaw-agent-db-DWI9Bgur.mjs"; import { b as mayShareAgentDatabaseFile, d as prepareOpenClawAgentDatabaseWorkerLease, f as readActiveOpenClawAgentDatabaseLeasesReadOnly } from "../openclaw-agent-db-lease-zP0JO4hP.mjs"; import { S as retainAgentDatabase, i as closeOpenClawAgentDatabaseByPath, v as recordOpenClawAgentDatabaseBackgroundVerification } from "../openclaw-agent-db-lifecycle-C9dal1XJ.mjs"; import { o as refreshOpenClawAgentDatabaseSchema, s as ensureOpenClawAgentDatabasePermissions } from "../openclaw-agent-db-schema-CppMSzFp.mjs"; import { s as verifyOpenClawStateLeaseOwnership } from "../openclaw-state-lease-storage-g4qzeMmW.mjs"; import { n as assertOpenClawStateLeaseWorkerOwnedInTransaction } from "../openclaw-state-lease-worker-Ddwq3QcA.mjs"; import { t as createWorkerOperationRegistry } from "../worker-operation-registry-DhUe8rTN.mjs"; import { n as assertAgentDeletionWorkerPredicate } from "../agent-deletion.worker-DuP8KOrz.mjs"; import { C as prepareAgentTranscript, E as requestRestrictedAgentDatabaseAdmission, S as prepareAgentNativeBindingOperation, T as createAgentDatabaseDomainOwner, _ as loadAgentTranscriptOperations, a as loadAgentEntryPatchOperations, b as loadConversationRegistryOperations, c as loadAgentMessageCutOperations, d as loadAgentProviderReviewOperations, f as loadAgentPurgeOperations, g as loadAgentTrajectoryOperations, h as loadAgentRestartRecoveryOperations, i as loadAgentCompoundOperations, l as loadAgentNativeBindingOperations, m as loadAgentReplacementOperations, n as loadAgentArchiveOperations, o as loadAgentEntryReadOperations, p as loadAgentReactionOperations, r as loadAgentArchivePruningOperations, s as loadAgentMaintenanceFinalizationOperations, t as loadAgentAcpOperations, u as loadAgentPendingInputOperations, v as loadAgentTranscriptReadOperations, x as loadUsageCacheOperations, y as loadConversationDeliveryOperations } from "../openclaw-agent-execution-operations-DpsVwNpq.mjs"; import { t as AGENT_FTS_SCHEMAS } from "../openclaw-agent-fts-schema-BY3B67St.mjs"; import { MessageChannel, MessagePort, isMainThread, receiveMessageOnPort, threadId } from "node:worker_threads"; //#region src/state/agent-deletion-cleanup.worker.ts const log = createSubsystemLogger("state/agent-deletion"); /** Keep lease grants separate from the agent command's commit and publication grants. */ function withLeaseAdmission(guard, run) { const { port1, port2 } = new MessageChannel(); let admission; try { requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "agent-deletion-lease", guard, port: port2 } }, [port2]); const received = receiveMessageOnPort(port1)?.message; if (!(received instanceof MessagePort)) throw new Error("Agent deletion lost its live lease admission"); admission = received; return run((operation) => withSqliteWorkerOperationAdmission({ port: received }, operation)); } finally { admission?.close(); port1.close(); port2.close(); } } /** The executing agent worker holds agent -> shared locks through the actual agent COMMIT. */ function withAgentDeletionWorkerCleanup(guard, target, run) { if (guard.lease.scope !== "core:agent-deletion" || guard.lease.key !== guard.predicate.agentId) throw new Error("Agent deletion requires its original target lease"); const assertSourceCurrent = () => { requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "agent-deletion-current", guard } }); target.assertFileCurrent(); }; const assertLease = (database) => { verifyOpenClawStateLeaseOwnership({ ...guard.lease, leaseLabel: "agent deletion", transaction: database.db }); }; const assertCurrent = () => { assertSourceCurrent(); const database = target.shared(); assertAgentDeletionWorkerPredicate(database, guard.predicate); assertLease(database); }; return withAgentDeletionWorkerDatabaseCleanup({ ...target, assertCurrent, assertJournal: (statePath, entries) => { if (statePath !== target.statePath || !entries.some((entry) => entry.agentId === guard.predicate.agentId && entry.operationId === guard.predicate.operationId && !entry.cleanupCompleted)) throw new Error(`Agent ${guard.predicate.agentId} deletion no longer owns database cleanup.`); assertSourceCurrent(); const database = target.shared(); assertAgentDeletionWorkerPredicate(database, guard.predicate, entries.find((entry) => entry.agentId === guard.predicate.agentId) ?? null); assertLease(database); return guard.predicate.agentId; }, withCommit: (commit) => { let committed = false; try { withLeaseAdmission(guard, (inLeaseAdmission) => runOpenClawStateWriteTransaction((database) => { inLeaseAdmission(() => assertOpenClawStateLeaseWorkerOwnedInTransaction(database.db, guard.lease)); assertAgentDeletionWorkerPredicate(database, guard.predicate); inLeaseAdmission(() => assertOpenClawStateLeaseWorkerOwnedInTransaction(database.db, guard.lease, "write", "commit")); assertSourceCurrent(); assertLease(database); commit(); committed = true; }, { database: target.shared(), path: target.statePath, env: target.env }, { operationLabel: "agent.deletion.agent-commit" })); } catch (error) { if (!committed) throw error; try { log.warn("Agent deletion committed, but releasing its state guard failed", { agentId: guard.predicate.agentId, error }); } catch {} } } }, run); } //#endregion //#region src/state/openclaw-agent-execution-close.ts /** Keep the native receipt and both cleanup modes with the same retirement owner. */ function createAgentDatabaseExecutionCloser(capture) { let receipt; return { [SQLITE_WORKER_CLOSE_RECEIPT]: () => receipt, closeAfterFailedOpen() { const { sharedBorrow, ...state } = capture(); receipt = void 0; receipt = closeAgentDatabaseExecution({ ...state, releaseSharedBorrow: () => sharedBorrow?.release() }); }, async close() { const { sharedBorrow, ...state } = capture(); receipt = void 0; await state.database?.walMaintenance.stop(); const errors = []; try { receipt = closeAgentDatabaseExecution({ ...state, releaseSharedBorrow: () => {} }); } catch (error) { errors.push(error); } try { await sharedBorrow?.releaseAsync(); } catch (error) { errors.push(error); } throwSqliteLifecycleErrors(errors, "Agent database cleanup failed"); } }; } function closeAgentDatabaseExecution({ database, identity, releasePreparations, closeDomain, releaseBorrow, releaseSharedBorrow }) { let checkpoint; const errors = []; for (const cleanup of [ ...releasePreparations, closeDomain, () => { if (!database) return; const closingPath = sqliteReaderDatabasePathKey(database.path); const stopObserving = onSqliteWalCheckpoint((observation) => { if (observation.databasePath === closingPath) checkpoint = { health: observation.health, observedAtNs: observation.observedAtNs, lastCompletedAtNs: observation.lastCompletedAtNs }; }); try { closeOpenClawAgentDatabaseByPath(database.path, database.agentId); } finally { stopObserving(); } }, () => releaseBorrow?.(), releaseSharedBorrow ]) try { cleanup(); } catch (error) { errors.push(error); } throwSqliteLifecycleErrors(errors, "Agent database cleanup failed"); if (identity && checkpoint) return { identity: { key: `file:${identity.physicalIdentity}`, canonicalPath: identity.nativeLocation }, incarnation: identity.incarnation, checkpoint }; } //#endregion //#region src/state/openclaw-agent-execution-incognito.worker.ts /** The ephemeral arm retains one native owner for every admitted operation. */ function createIncognitoAgentDatabaseBackend(input, opening) { const options = { agentId: input.agentId, path: input.databasePath, env: input.environment }; if (isMainThread || opening.databasePath !== input.databasePath || opening.target?.kind !== "ephemeral" || opening.target.handle !== input.identity.handle || opening.target.incarnation !== input.identity.incarnation || !isIncognitoOpenClawAgentSqlitePath(input.databasePath, options)) throw new Error("Incognito open differs from its worker-owned target"); try { requestSqliteWorkerOperationAdmission({ stage: "open", facts: input }); } catch (error) { throw new SqliteWorkerOpenRefusedError(error); } if (getOpenClawAgentDatabaseIfOpen(options)) throw new Error("Incognito actor cannot adopt another native database"); const database = openOpenClawAgentDatabase(options); const release = retainAgentDatabase(database.db); let closed = false; const close = () => { closed = true; closeOpenClawAgentDatabaseByPath(database.path, database.agentId); release(); }; try { if (database.db.location()) throw new Error("Incognito actor requires memory-only SQLite storage"); requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { identity: input.identity } }); } catch (error) { try { close(); } catch (cleanupError) { throw createSqliteLifecycleAggregateError([error, cleanupError], "Incognito open and cleanup failed", error); } throw error; } const assertCurrent = () => { if (closed || !database.db.isOpen || getOpenClawAgentDatabaseIfOpen(options) !== database) throw new Error("Incognito actor lost its retained native database"); }; let sessions; return { async prepare(command) { if (!sessions) { const { createIncognitoSessionWorker } = await import("../session-incognito.worker-BdIPwNPH.mjs"); sessions = createIncognitoSessionWorker(database, input.identity, input.environment); } await sessions.prepare(command); }, execute(command) { assertCurrent(); requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { identity: input.identity } }); if (!sessions) throw new Error("Incognito session operation was not prepared"); return sessions.execute(command); }, assertSettled() { assertCurrent(); sessions?.assertSettled(); if (database.db.isTransaction) throw new Error("Incognito command left an unsettled native transaction"); }, close() { sessions?.close(); close(); } }; } //#endregion //#region src/state/openclaw-agent-execution-maintenance.ts /** Metadata preparation and commit share the canonical actor's retained snapshots. */ function createAgentDatabaseMaintenanceOwner(context) { const preparations = /* @__PURE__ */ new Map(); let maintenance; let replacements; const releasePreparation = (id) => { const preparation = preparations.get(id); if (preparation) { preparation.prepared.release(); preparations.delete(id); } }; return { operations: { "session.maintenance.read": (plan) => { context.assertFileIdentity(); return { kind: "session-maintenance-read", result: expectDefined(maintenance, "Session maintenance kernel").readSessionMaintenanceInWorker({ ...plan, databaseOptions: context.databaseOptions }, context.readPreparedDatabase()), workerThreadId: threadId }; }, "session.maintenance.release": ({ id }) => releasePreparation(id), "session.maintenance.prepare": (input) => { const kernel = expectDefined(maintenance, "Session maintenance kernel"); context.assertFileIdentity(); if (preparations.has(input.id)) throw new Error("Session maintenance preparation is already retained"); if (preparations.size >= 2) throw new Error("Session maintenance preparation capacity is occupied"); const prepared = kernel.prepareSessionMaintenanceInWorker({ kind: "maintenance-plan", input: input.input, ageOwner: input.ageOwner, ageChanges: input.ageChanges, databaseOptions: context.databaseOptions }); preparations.set(input.id, { plan: input, prepared }); }, "session.maintenance.metadata": (input) => { const kernel = expectDefined(maintenance, "Session maintenance kernel"); const preparePublication = expectDefined(replacements, "Session replacement kernel").prepareSessionEntryReplacementPublication; const opened = context.openWriter(); const previous = /* @__PURE__ */ new Map(); const current = /* @__PURE__ */ new Map(); let publication; const preparation = input.kind === "maintenance-plan" ? expectDefined(preparations.get(input.preparationId), "Session maintenance preparation") : void 0; if (preparation && input.kind === "maintenance-plan") Object.assign(preparation.plan.input, input.protection); const plan = input.kind === "maintenance-plan" ? { ...expectDefined(preparation, "Session maintenance preparation").plan, kind: "maintenance-plan" } : input; const value = kernel.runSessionMaintenanceMetadataInTransaction({ ...plan, databaseOptions: context.databaseOptions }, { beforeMutation(database) { if (database.db !== opened.db) throw new Error("Session maintenance lost its canonical database owner"); context.admit("transaction"); }, onArchived(sessionKey, before, after) { previous.set(sessionKey, before); current.set(sessionKey, after); }, beforeCommit(database) { publication = preparePublication({ pendingArchiveRecovery: false, previous, current, maintenancePlans: [], membershipInvalidatedKeys: [] }, database); deferSqliteWorkerCommitReceipt(database.db, publication); context.admit("commit", publication); } }, preparation?.prepared); return value.kind === "maintenance-preservation-required" || value.kind === "maintenance-plan-stale" ? { kind: "not-committed", workerThreadId: threadId, value } : { kind: "committed", workerThreadId: threadId, value, publication: expectDefined(publication, "Session maintenance commit receipt") }; } }, prepare() { return Promise.all([import("../session-accessor.sqlite-maintenance-transaction-wDLc5AtK.mjs"), import("../session-accessor.sqlite-replacement-state-h7Yz1bCz.mjs")]).then(([metadata, replacement]) => { maintenance = metadata; replacements = replacement; }); }, cleanup(input) { if (input.kind === "maintenance-plan") releasePreparation(input.preparationId); }, getPreparationReleases() { return [...preparations.keys()].map((id) => () => releasePreparation(id)); } }; } //#endregion //#region src/state/openclaw-agent-execution-voice-operations.ts async function loadAgentVoiceSessionOperations() { const { readSessionSourceValidation } = await import("../session-source-predicate.worker-B4Tq5g8W.mjs"); const kernel = await import("../client-voice-session-write.kernel-BcBu0bNP.mjs"); const store = await import("../client-voice-session-store-Ct-PKLtv.mjs"); const entries = await import("../session-accessor.sqlite-entry-read-Cdmo5WHm.mjs"); const keys = await import("../session-accessor.sqlite-scope-helpers-HJr7Z-dj.mjs"); const canonical = await import("../session-canonical-key-GVDAgytN.mjs"); const { isIncognitoSessionKey } = await import("../incognito-session-key-B-JIffX5.mjs"); const { readSessionPendingInputAuthorityFactsInTransaction } = await import("../session-pending-input-authority.kernel-BZVfoqXF.mjs"); return { "voice.session.read": (input, { open }) => { const database = open(); const record = store.readVoiceSessionRecordInTransaction(database, input.voiceSessionId); let entry; if (record && record.effects.length > 0 && !record.digestDeliveredAt && !isIncognitoSessionKey(record.sessionKey)) { canonical.assertCanonicalSqliteSessionKeysCurrent(database); const key = keys.resolveSqliteSessionKey(record.sessionKey, database.agentId); entry = entries.prepareExactSessionEntryRowReads(database, [key], "delivery", "canonical")(key)?.entry; } return { record, entry }; }, "voice.session.mutate": (input, { writeTransaction, admit }) => writeTransaction(`voice.session.${input.kind}`, "Voice session", (database) => { const sourceFacts = input.transactionSource ? readSessionPendingInputAuthorityFactsInTransaction(database, input.transactionSource.sessionKey, input.transactionSource.agentId) : void 0; const sourceValidation = readSessionSourceValidation(database, input.sources); if (sourceFacts || input.sources?.length) admit("transaction", { kind: "voice-session-authority", facts: sourceFacts, sourceValidation }); if (sourceValidation.refusedSource) throw new Error("Voice session source refusal was not rejected"); const entry = input.kind === "reserve" && input.transcriptSessionKey ? entries.readSessionEntryIdentity(database, keys.resolveSqliteSessionKey(input.transcriptSessionKey, database.agentId)) : void 0; if (input.kind === "reserve" && input.transcriptSessionKey && !entry?.sessionId) throw new Error(`agent session not found (${input.sessionKey})`); const result = { record: kernel.mutateVoiceSessionInDatabase(database, input), entry }; deferSqliteWorkerCommitReceipt(database.db, result); admit("commit", sourceFacts ? { kind: "voice-session-authority", facts: sourceFacts } : void 0); return result; }) }; } //#endregion //#region src/state/openclaw-agent-startup-fts.ts /** The native worker repairs only owned FTS under its existing shared write fence. */ function repairAgentDatabaseStartupFts(context) { const { receipt, check, error } = context; if (!(error instanceof Error) || error.name !== "SqliteIntegrityError" || error.cause || check.databaseLabel !== receipt.path || !classifySqliteFtsIntegrityFindings(check.database, readSqliteIntegrityFindings(check.database), AGENT_FTS_SCHEMAS)) return false; return runOpenClawStateWriteTransaction((shared) => { const admit = (phase, message) => { context.assertCurrent(); context.assertFileIdentity(); requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "agent-startup-fts", phase, lease: receipt, message, agentDeletionJournalPresent: readAgentDeletionJournalStatusInDatabase(shared.db, receipt.agentId) !== "absent" } }); }; context.assertCurrent(); context.assertFileIdentity(); const owners = readActiveOpenClawAgentDatabaseLeasesReadOnly({ env: context.env, path: receipt.sharedStatePath }).filter((owner) => mayShareAgentDatabaseFile(owner.path, receipt.path)); if (owners.length !== 1 || owners[0]?.lease_id !== receipt.leaseId) throw new Error("Startup FTS repair requires an exclusive live agent database lease"); admit("begin"); admit("complete", repairDoctorSqliteIndexCorruption(check.database, check.databaseLabel, { label: "agent " + receipt.agentId, ftsSchemas: AGENT_FTS_SCHEMAS, ftsOnly: true, assertCurrent: () => admit("check"), describeRepair: (indexes) => "Rebuilt stale SQLite FTS indexes (agent " + receipt.agentId + "): " + indexes.join(", ") + ". No table rows were removed." }).join(" ")); return true; }, { env: context.env, path: receipt.sharedStatePath }); } //#endregion //#region src/state/openclaw-agent-execution.worker.ts function createSqliteWorkerBackend(input, opening) { if (input.kind === "ephemeral") return createIncognitoAgentDatabaseBackend(input, opening); const backend = openAgentDatabaseBackend(input, opening); try { backend.execute({ type: "database.prepareWrite", input: void 0 }); backend.assertSettled?.(); return backend; } catch (error) { try { backend.closeAfterFailedOpen(); } catch (cleanupError) { throw createSqliteLifecycleAggregateError([error, cleanupError], "Agent creation and cleanup failed", error); } throw error; } } /** The broker supplies a private admission channel before invoking this native factory. */ const openExistingSqliteWorkerBackend = openAgentDatabaseBackend; function openAgentDatabaseBackend(input, opening) { if (opening.databasePath !== input.databasePath) throw new Error("Agent database open does not match its captured execution owner"); const admitOpen = () => { try { requestSqliteWorkerOperationAdmission({ stage: "open", facts: input }); } catch (error) { throw new SqliteWorkerOpenRefusedError(error); } }; admitOpen(); const options = { agentId: input.agentId, path: input.databasePath, env: input.environment }; let admittedFileIdentity = input.creatingIdentity?.key ?? opening.existingIdentity ?? readDatabasePathIdentitySync(input.databasePath).key; let admittedFileBirthtime = input.creatingIdentity?.birthtime; const assertFileIdentity = () => { if (input.expectedIdentity) assertExistingDatabaseIdentity(input.databasePath, `file:${input.expectedIdentity.physicalIdentity}`, input.expectedIdentity.birthtime); const pathOnly = admittedFileIdentity.startsWith("path:"); if (pathOnly || input.creatingIdentity) { const current = readDatabasePathIdentitySync(input.databasePath); if (pathOnly && current.key !== admittedFileIdentity || input.creatingIdentity && current.canonicalPath !== input.creatingIdentity.canonicalPath) throw new Error("Agent database target changed before creating open"); } if (!pathOnly) assertExistingDatabaseIdentity(input.databasePath, admittedFileIdentity, admittedFileBirthtime); }; let database; let shared; let sharedBorrow; let releaseBorrow; let identity; let openingFailure; let startupJournalRequested = false; let publicationPreparation; const readRequestPreparation = () => { const attachment = takeSqliteWorkerOperationAdmissionAttachment(); if (!isRecord(attachment) || attachment.kind !== "agent-execution" || typeof attachment.startupJournal !== "boolean") throw new Error("Agent execution requires its request-local preparation facts"); return { startupJournal: attachment.startupJournal, deletion: attachment.deletion }; }; const openShared = () => { if (!shared) { shared = openOpenClawStateDatabase({ path: input.stateDatabasePath, env: input.environment, initializationAgentPaths: [input.databasePath] }); sharedBorrow = retainOpenClawStateDatabase(shared); } return shared; }; const withPreparation = (preparation, run) => { startupJournalRequested = preparation.startupJournal; try { return preparation.deletion ? withAgentDeletionWorkerCleanup(preparation.deletion, { agentId: input.agentId, path: input.databasePath, statePath: input.stateDatabasePath, env: input.environment, shared: openShared, assertFileCurrent: assertFileIdentity }, run) : run(); } finally { startupJournalRequested = false; } }; const readDeletionJournal = () => readAgentDeletionJournalStatusInDatabase(expectDefined(shared, "Agent execution shared-state owner").db, input.agentId) !== "absent"; const openClaimedWriter = (refreshSchema = false) => { let validation; if (!database) { admitOpen(); assertFileIdentity(); const sharedDatabase = openShared(); const lease = prepareOpenClawAgentDatabaseWorkerLease(options, sharedDatabase, input.leaseId); const { port1, port2 } = new MessageChannel(); try { requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "shared-owner", identity: requireOpenClawStateDatabaseIdentity(sharedDatabase), lease: lease.receipt, validationPort: port2 } }, [port2]); const preparation = receiveMessageOnPort(port1)?.message; lease.validation = preparation.validation; lease.deferUnverifiedIntegrity = preparation.deferUnverifiedIntegrity; lease.startupRepair = startupJournalRequested ? (check, error, assertCurrent) => repairAgentDatabaseStartupFts({ receipt: lease.receipt, check, error, assertCurrent, assertFileIdentity, env: options.env }) : void 0; } catch (error) { throw new SqliteWorkerOpenRefusedError(error); } finally { port1.close(); port2.close(); } assertFileIdentity(); let registration; let openingResult; try { const opened = openOpenClawAgentDatabase(options, lease, { starting: () => requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "agent-registration-start", lease: lease.receipt } }), committed(receipt) { registration = receipt; } }); database = opened; releaseBorrow = retainAgentDatabase(opened.db); openingResult = { ok: true, value: opened }; } catch (error) { openingFailure = { error }; openingResult = { ok: false, error }; } if (registration) try { requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { kind: "agent-registration-committed", registration } }); } catch (error) { if (!openingResult.ok) throw createSqliteLifecycleAggregateError([openingResult.error, error], `${String(openingResult.error)}; committed registration reporting failed: ${String(error)}`, openingResult.error); throw error; } if (!openingResult.ok) throw openingResult.error; const opened = openingResult.value; const nativeIdentity = readOpenClawAgentDatabaseIdentity(opened); if (typeof nativeIdentity.identity !== "string") throw new Error("Disk agent execution requires its canonical file identity"); const openedFileIdentity = `file:${nativeIdentity.identity}`; if (admittedFileIdentity.startsWith("file:") && (openedFileIdentity !== admittedFileIdentity || admittedFileBirthtime !== void 0 && nativeIdentity.birthtime !== admittedFileBirthtime)) throw new Error("Agent writer differs from its admitted physical file"); if (input.expectedIdentity && nativeIdentity.identity !== input.expectedIdentity.physicalIdentity) throw new Error("Agent writer differs from its expected physical file"); admittedFileIdentity = openedFileIdentity; admittedFileBirthtime = nativeIdentity.birthtime; identity = { kind: "file", physicalIdentity: nativeIdentity.identity, birthtime: nativeIdentity.birthtime, incarnation: nativeIdentity.incarnation, nativeLocation: nativeIdentity.filename }; validation = getOpenClawAgentDatabaseValidation(opened); } if (!database || !database.db.isOpen || getOpenClawAgentDatabaseIfOpen(options) !== database) throw new Error("Agent execution lost its retained native database"); if (refreshSchema) validation = refreshOpenClawAgentDatabaseSchema(database, admitOpen); requestSqliteWorkerOperationAdmission({ stage: "prepare", facts: { identity, validation, ...startupJournalRequested ? { agentDeletionJournalPresent: readDeletionJournal() } : {} } }); return database; }; const openWriter = (refreshSchema = false) => input.creationClaim ? withAgentCreationClaimWitness(input.creationClaim, admitOpen, () => openClaimedWriter(refreshSchema)) : openClaimedWriter(refreshSchema); const admit = (stage, publication, requestAdmission) => { assertFileIdentity(); const request = { stage, facts: { identity, ...startupJournalRequested ? { agentDeletionJournalPresent: readDeletionJournal() } : {}, ...publication ? { publication } : {} } }; requestRestrictedAgentDatabaseAdmission(request, requestAdmission); if (stage === "commit") ensureOpenClawAgentDatabasePermissions(input.databasePath, options); }; const writeTransaction = (operationLabel, owner, write) => { const opened = openWriter(); return runOpenClawAgentWriteTransaction((current) => { if (current.db !== opened.db) throw new Error(`${owner} lost its canonical database owner`); admit("transaction"); return write(current); }, options, { operationLabel }); }; const maintenance = createAgentDatabaseMaintenanceOwner({ databaseOptions: options, assertFileIdentity, openWriter, readPreparedDatabase() { assertFileIdentity(); return expectDefined(database, "Maintenance read requires its admitted native owner"); }, admit }); const loadMaintenanceOperations = async () => maintenance.operations; const registry = createWorkerOperationRegistry({ "session.entry.read": loadAgentEntryReadOperations, "voice.session.read": loadAgentVoiceSessionOperations, "voice.session.mutate": loadAgentVoiceSessionOperations, "session.entry.patch.prepare": loadAgentEntryPatchOperations, "session.entry.patch.commit": loadAgentEntryPatchOperations, "session.turn.prepare": loadAgentCompoundOperations, "session.turn.commit": loadAgentCompoundOperations, "session.lifecycle.reset": loadAgentCompoundOperations, "session.lifecycle.project": loadAgentCompoundOperations, "session.agentPurge.prepare": loadAgentPurgeOperations, "session.agentPurge.commit": loadAgentPurgeOperations, "session.maintenance.finalize": loadAgentMaintenanceFinalizationOperations, "session.maintenance.size": loadAgentMaintenanceFinalizationOperations, "session.nativeBindings.delete": loadAgentNativeBindingOperations, "session.messageCut.commit": loadAgentMessageCutOperations, "trajectory.events.append": loadAgentTrajectoryOperations, "trajectory.retention.begin": loadAgentTrajectoryOperations, "trajectory.retention.delete": loadAgentTrajectoryOperations, "session.archives.preparePublication": loadAgentArchiveOperations, "session.archives.recordPublication": loadAgentArchiveOperations, "session.transcript.initialize": loadAgentTranscriptOperations, "session.transcript.rawDelta.read": loadAgentTranscriptReadOperations, "session.transcript.watermark.read": loadAgentTranscriptReadOperations, "session.transcript.visibleDelta.read": loadAgentTranscriptReadOperations, "session.transcript.memoryCapture.read": loadAgentTranscriptReadOperations, "session.transcript.anchors.read": loadAgentTranscriptReadOperations, "session.transcript.coldMetadata.read": loadAgentTranscriptReadOperations, "session.entries.replace": loadAgentReplacementOperations, "session.restart.recover": loadAgentRestartRecoveryOperations, "session.entry.acp": loadAgentAcpOperations, "session.providerReview.compare": loadAgentProviderReviewOperations, "session.reaction.set": loadAgentReactionOperations, "conversation.delivery.begin": loadConversationDeliveryOperations, "conversation.register": loadConversationRegistryOperations, "conversation.authority": loadConversationRegistryOperations, "conversation.delivery.transition": loadConversationDeliveryOperations, "session.pendingInputs.withdraw": loadAgentPendingInputOperations, "session.pendingInputs.read": loadAgentPendingInputOperations, "session.pendingInputs.mutate": loadAgentPendingInputOperations, "session.pendingInputs.interruptHistory": loadAgentPendingInputOperations, "session.archivePruning.deletePublished": loadAgentArchivePruningOperations, "session.archivePruning.pruneRetention": loadAgentArchivePruningOperations, "session.archivePruning.removeLegacy": loadAgentArchivePruningOperations, "session.archivePruning.reclaimPages": loadAgentArchivePruningOperations, "session.maintenance.prepare": loadMaintenanceOperations, "session.maintenance.read": loadMaintenanceOperations, "session.maintenance.metadata": loadMaintenanceOperations, "session.maintenance.release": loadMaintenanceOperations, "usageCache.writeRollup": loadUsageCacheOperations, "usageCache.prune": loadUsageCacheOperations, "usageCache.acquireLock": loadUsageCacheOperations, "usageCache.releaseLock": loadUsageCacheOperations }); const context = { open: openWriter, options, admit, writeTransaction, writeSharedTransaction(source, write) { const retained = expectDefined(shared, "Native binding shared-state owner"); const sharedIdentity = requireOpenClawStateDatabaseIdentity(retained); if (sharedIdentity.key !== source.key || sharedIdentity.canonicalPath !== source.canonicalPath || sharedIdentity.birthtime !== source.birthtime) throw new Error("Native binding settlement changed its captured shared-state owner"); assertExistingDatabaseIdentity(source.canonicalPath, source.key, source.birthtime); return runOpenClawStateWriteTransaction(write, { database: retained, path: retained.path, env: input.environment }, { operationLabel: "session.native-binding.settlement" }); } }; const domain = createAgentDatabaseDomainOwner({ databasePath: input.databasePath, assertCurrent() { assertOpen(); const current = openWriter(); assertFileIdentity(); return current.db; }, assertCleanupCurrent() { if (!database || !identity || !database.db.isOpen || normalizeDatabasePath(database.db.location() ?? "") !== identity.nativeLocation || getOpenClawAgentDatabaseIfOpen(options) !== database) throw new Error("Agent cleanup lost its retained native database"); assertFileIdentity(); }, admit: (stage, requestAdmission) => admit(stage, void 0, requestAdmission) }); let closed = false; const assertOpen = () => { if (closed) throw new Error("Agent database execution owner is closed"); }; const executeCommand = (command) => { if (command.type === "database.domain.bind" || command.type === "database.domain.publish" || command.type === "database.domain.execute" || command.type === "database.domain.close") return domain.execute(command); if (command.type === "database.prepareWrite") { openWriter(true); return; } if (command.type === "database.recordIntegrity") { const opened = openWriter(); admit("transaction"); return recordOpenClawAgentDatabaseBackgroundVerification(opened, () => admit("commit")); } if (command.type === "database.walMaintenance") return openWriter().walMaintenance.maintainPeriodic?.(command.input, admit) ?? { reclaimedPages: 0 }; return registry.execute(command, context); }; return { ...createAgentDatabaseExecutionCloser(() => { closed = true; return { database, identity, releasePreparations: maintenance.getPreparationReleases(), closeDomain: () => domain.close(), releaseBorrow, sharedBorrow }; }), prepare(command) { if (command.type === "database.domain.bind" || command.type === "database.domain.publish" || command.type === "database.domain.execute" || command.type === "database.domain.close") return domain.prepare(command); const preparing = registry.prepare(command.type); if (command.type === "session.turn.commit" && command.input.options.voiceTranscript) return Promise.all([preparing, import("../session-turn.worker--GjV6of9.mjs").then((turn) => turn.prepareVoiceTranscriptCommit())]).then(() => {}); const nativeBindings = command.type === "session.nativeBindings.delete" ? command.input : command.type === "session.messageCut.commit" ? command.input.nativeBindings : command.type === "session.agentPurge.commit" || command.type === "session.maintenance.finalize" ? command.input.nativeBindings : void 0; if (nativeBindings) return Promise.all([preparing, prepareAgentNativeBindingOperation(nativeBindings, input.environment)]).then(() => {}); if (command.type === "session.maintenance.prepare" || command.type === "session.maintenance.read" || command.type === "session.maintenance.metadata") return Promise.all([preparing, maintenance.prepare()]).then(() => {}); if (command.type === "session.entries.replace" && command.input.initializeTranscript) return Promise.all([preparing, prepareAgentTranscript()]).then(() => {}); return preparing; }, [SQLITE_WORKER_PREPARE_ADMITTED](command) { if (command.type !== "database.domain.publish") return; publicationPreparation = readRequestPreparation(); return withPreparation(publicationPreparation, () => domain.preparePublication(command.input)); }, [SQLITE_WORKER_OPERATION_CLEANUP](command) { if (command.type === "session.maintenance.metadata") maintenance.cleanup(command.input); if (command.type === "database.domain.publish") try { withPreparation(publicationPreparation ?? { startupJournal: false }, () => domain.cleanupPublication(command.input.id)); } finally { publicationPreparation = void 0; } }, assertSettled() { if (openingFailure) throw openingFailure.error; domain.assertSettled(); if (shared) { assertTransactionUsable(shared.db); if (!shared.db.isOpen || shared.db.isTransaction) throw new Error("Agent database command left its shared-state participant unsettled"); } if (database) { assertTransactionUsable(database.db); if (!identity || !database.db.isOpen || database.db.isTransaction) throw new Error("Agent database command left an unsettled native connection"); } }, execute(command) { assertOpen(); if (command.type === "database.domain.publish") { if (publicationPreparation === void 0) throw new Error("Agent publication lost its request-local preparation facts"); return withPreparation(publicationPreparation, () => executeCommand(command)); } return withPreparation(readRequestPreparation(), () => executeCommand(command)); } }; } //#endregion export { createSqliteWorkerBackend, openExistingSqliteWorkerBackend };