openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
214 lines (213 loc) • 9.18 kB
JavaScript
import { c as isRecord } from "../../record-coerce-TIsquoVR.mjs";
import { c as readDatabasePathIdentitySync } from "../../sqlite-worker-identity-B_aK_kcL.mjs";
import { t as assertTransactionUsable } from "../../sqlite-transaction-DlnLAQiX.mjs";
import { t as encodeOpenClawStateWorkerError } from "../../openclaw-state-worker-error-PbHiriY7.mjs";
import { r as getSqliteWorkerStateContext } from "../../sqlite-worker-state-context-ifl-DKqr.mjs";
import { c as resolveOpenClawAgentSqlitePath } from "../../openclaw-agent-db.paths-DiWMV5LG.mjs";
import { d as runOpenClawAgentWriteTransaction } from "../../openclaw-agent-db-CFSa_Qik.mjs";
import { a as prepareTranscriptPayloadForReuse } from "../../transcript-payload-Dph8Bvhj.mjs";
import { t as SessionTranscriptWriterClaimReboundError } from "../../transcript-write-context-DdT_6wqt.mjs";
import { _ as toDatabaseOptions, m as resolveSqliteTranscriptScope } from "../../session-accessor.sqlite-scope-Dovl36Ht.mjs";
import { n as assertCanonicalSessionKeyWrite } from "../../session-canonical-key-DKUMSxwU.mjs";
import { a as runWithSessionTranscriptReadFence } from "../../session-transcript-read-fence--kRTH14M.mjs";
import { t as readSessionTranscriptBoundedActiveContextCore } from "../../session-accessor.sqlite-active-context-DgfzopEd.mjs";
import { t as ensureSessionEntryInTransaction } from "../../session-accessor.sqlite-initial-entry-Ccq2rVSq.mjs";
import { a as appendTranscriptMessageSnapshotSync, n as appendTranscriptEventSnapshotSync, w as readTranscriptMutationAtSync } from "../../session-accessor.sqlite-transcript-write-DZbFltlG.mjs";
import { O as validatePreparedAssistantAppendSync, a as inspectTranscriptEventsSync, f as loadTranscriptReadSnapshotSync } from "../../session-accessor.sqlite-read-CAR7IGtb.mjs";
import { serialize } from "node:v8";
//#region src/agents/sessions/session-manager-metadata.worker.ts
function copyTranscriptRefusal(value) {
if (value === void 0) return;
if (!isRecord(value) || typeof value.agentIdHash !== "string" || typeof value.expectedSessionIdHash !== "string" || typeof value.sessionKeyHash !== "string") throw new Error("Session metadata refusal has an invalid identity");
const identity = {
agentIdHash: value.agentIdHash,
expectedSessionIdHash: value.expectedSessionIdHash,
sessionKeyHash: value.sessionKeyHash
};
if (value.code === "session-entry-missing") return {
...identity,
code: value.code
};
if (value.code === "session-rebound" && typeof value.actualSessionIdHash === "string") return {
...identity,
code: value.code,
actualSessionIdHash: value.actualSessionIdHash
};
throw new Error("Session metadata refusal has an invalid kind");
}
function readCommittedMetadataView(scope, limits, admission) {
return runWithSessionTranscriptReadFence(admission, () => {
if (limits) return {
kind: "bounded",
snapshot: readSessionTranscriptBoundedActiveContextCore(scope, {
...limits,
...admission !== void 0 ? { ignoreReadFence: true } : {}
})
};
if (admission !== void 0) {
const inspected = inspectTranscriptEventsSync(scope);
return {
kind: "full",
snapshot: {
events: inspected.events,
version: {
generation: inspected.snapshot.generation,
rawSeq: inspected.snapshot.lastSeq,
updatedAt: inspected.snapshot.transcriptUpdatedAt
}
}
};
}
return {
kind: "full",
snapshot: loadTranscriptReadSnapshotSync(scope)
};
});
}
/** Borrow the canonical actor's connection; this domain never opens or closes a database. */
function bindSqliteWorkerBackend(_input, context) {
let closed = false;
const assertOpen = () => {
if (closed || !context.database.isOpen) throw new Error("Session metadata domain is closed");
assertTransactionUsable(context.database);
};
const execute = (command) => {
assertOpen();
const scope = {
...command.input.scope,
env: getSqliteWorkerStateContext().environment
};
const resolved = resolveSqliteTranscriptScope(scope);
const options = toDatabaseOptions(resolved);
if (readDatabasePathIdentitySync(resolveOpenClawAgentSqlitePath(options)).canonicalPath !== context.databasePath) throw new Error("Session metadata target changed its database owner");
scope.storePath = context.databasePath;
resolved.path = context.databasePath;
options.path = context.databasePath;
if (command.type === "session.metadata.mutation") return {
ok: true,
value: readTranscriptMutationAtSync(scope)
};
assertCanonicalSessionKeyWrite(resolved.sessionKey, resolved.agentId);
if (command.type === "session.transcript.appendMessage") return runOpenClawAgentWriteTransaction((database) => {
if (database.db !== context.database) throw new Error("Session message lost its borrowed canonical connection");
context.admit("transaction");
let projectionNeedsReconcile = false;
const snapshot = appendTranscriptMessageSnapshotSync(scope, {
message: command.input.message,
cwd: command.input.cwd
}, void 0, {
messageAlreadyRedacted: true,
scheduleProjectionReconcile: false,
onProjectionReconcileNeeded: () => {
projectionNeedsReconcile = true;
}
});
context.admit("commit");
return {
ok: true,
value: {
snapshot,
projectionNeedsReconcile
}
};
}, options, { operationLabel: command.type });
if (command.type === "session.metadata.append" && command.input.event.type === "message") {
const { event, message } = command.input;
if (!message) throw new Error("Session message append requires prepared storage bytes");
const { message: _message, ...envelope } = event;
const eventJson = `${JSON.stringify(envelope).slice(0, -1)},"message":${message.prepared.messageJson}}`;
message.prepared.physicalPayload = prepareTranscriptPayloadForReuse(context.database, eventJson, {
...envelope,
message: message.prepared.persistedMessage
});
if (message.validateTurn) {
const mutationAt = validatePreparedAssistantAppendSync(scope, event.parentId, command.input.view?.admission?.entryId);
if (mutationAt === void 0) {
const error = /* @__PURE__ */ new Error(`SQLite transcript changed while preparing rewrite for ${scope.sessionId}`);
error.name = "SqliteTranscriptMutationConflictError";
throw error;
}
command.input.options.expectedMutationAt = mutationAt;
}
}
const outcome = runOpenClawAgentWriteTransaction((database) => {
if (database.db !== context.database) throw new Error("Session metadata lost its borrowed canonical connection");
context.admit("transaction");
if (command.type === "session.metadata.initialize") {
const result = ensureSessionEntryInTransaction(database, resolved, scope, command.input.entry, command.input.initialWriterRunId);
context.admit("commit");
return {
ok: true,
value: result
};
}
let projectionNeedsReconcile = false;
const projection = {
scheduleProjectionReconcile: false,
onProjectionReconcileNeeded: () => {
projectionNeedsReconcile = true;
}
};
const { event, message } = command.input;
const snapshot = event.type === "message" && message ? appendTranscriptMessageSnapshotSync(scope, {
...command.input.options,
message: event.message,
eventId: event.id,
parentId: event.parentId,
now: Date.parse(event.timestamp),
cwd: message.cwd,
idempotencyLookup: message.idempotencyLookup
}, message.prepared, projection) : appendTranscriptEventSnapshotSync(scope, event, command.input.options, projection);
context.admit("commit");
return {
ok: true,
value: {
snapshot,
projectionNeedsReconcile
}
};
}, options, { operationLabel: command.type });
if (command.type === "session.metadata.append" && command.input.event.type !== "session" && command.input.view && outcome.ok && "snapshot" in outcome.value && outcome.value.snapshot.ok) {
const { event, view } = command.input;
const committed = outcome.value.snapshot.value;
if (!committed.result?.appended) return outcome;
const version = view.loadedVersion;
const effectiveParentId = committed.result.effectiveParentId;
if (version && (committed.before.generation !== version.generation || committed.before.rawSeq !== version.rawSeq) || effectiveParentId !== void 0 && effectiveParentId !== event.parentId) try {
outcome.value.reload = {
ok: true,
value: readCommittedMetadataView(scope, view.limits, view.admission)
};
serialize(outcome);
} catch (error) {
outcome.value.reload = {
ok: false,
error: encodeOpenClawStateWorkerError(error, { includeOrdinary: true })
};
}
}
return outcome;
};
return {
execute(command) {
try {
return execute(command);
} catch (error) {
if (error instanceof SessionTranscriptWriterClaimReboundError) return {
ok: false,
refusal: copyTranscriptRefusal(error.cause)
};
throw error;
}
},
assertSettled() {
assertOpen();
if (context.database.isTransaction) throw new Error("Session metadata command left a transaction open");
},
close() {
closed = true;
}
};
}
//#endregion
export { bindSqliteWorkerBackend };