openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
340 lines (339 loc) • 12.8 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js";
import { c as isRecord } from "./utils-CCC-BEJH.js";
import { d as executeSqliteQuerySync, f as executeSqliteQueryTakeFirstSync, i as openOpenClawStateDatabase, o as runOpenClawStateWriteTransaction, p as getNodeSqliteKysely } from "./openclaw-state-db-ULtH_b7x.js";
import { c as parseAgentSessionKey } from "./session-key-utils-Bx3apsJ3.js";
import { i as getRuntimeConfig } from "./io-Gi7-pyU-.js";
import "./config-C9RxTsn1.js";
import { u as resolveStorePath } from "./paths-NEwU8m3X.js";
import { t as loadSessionStore } from "./store-load-C4uq6Lrq.js";
import { r as mergeSessionEntry } from "./types-D8S_uNvu.js";
//#region src/acp/runtime/session-meta.ts
let sessionStoreRuntimePromise;
function loadSessionStoreRuntime() {
sessionStoreRuntimePromise ??= import("./store.runtime.js");
return sessionStoreRuntimePromise;
}
function resolveStoreSessionKey(store, sessionKey) {
const normalized = sessionKey.trim();
if (!normalized) return "";
if (store[normalized]) return normalized;
const lower = normalizeLowercaseStringOrEmpty(normalized);
if (store[lower]) return lower;
for (const key of Object.keys(store)) if (normalizeLowercaseStringOrEmpty(key) === lower) return key;
return lower;
}
/** Resolves the session store path that owns an ACP session key. */
function resolveSessionStorePathForAcp(params) {
const cfg = params.cfg ?? getRuntimeConfig();
const parsed = parseAgentSessionKey(params.sessionKey);
return {
cfg,
storePath: resolveStorePath(cfg.session?.store, {
agentId: parsed?.agentId,
env: params.env
})
};
}
function getAcpSessionKysely(db) {
return getNodeSqliteKysely(db);
}
function parseOptionalJsonRecord(raw) {
if (raw == null || raw === "") return;
try {
const parsed = JSON.parse(raw);
return isRecord(parsed) ? parsed : void 0;
} catch {
return;
}
}
function rowToAcpSessionMeta(row) {
const identity = parseOptionalJsonRecord(row.identity_json);
const runtimeOptions = parseOptionalJsonRecord(row.runtime_options_json);
return {
backend: row.backend,
agent: row.agent,
runtimeSessionName: row.runtime_session_name,
...identity ? { identity } : {},
mode: row.mode === "oneshot" ? "oneshot" : "persistent",
...runtimeOptions ? { runtimeOptions } : {},
...row.cwd != null ? { cwd: row.cwd } : {},
state: row.state === "running" || row.state === "error" ? row.state : "idle",
lastActivityAt: row.last_activity_at,
...row.last_error != null ? { lastError: row.last_error } : {}
};
}
function bindAcpSessionMeta(params) {
return {
session_key: params.sessionKey,
session_id: params.sessionId ?? null,
backend: params.meta.backend,
agent: params.meta.agent,
runtime_session_name: params.meta.runtimeSessionName,
identity_json: params.meta.identity ? JSON.stringify(params.meta.identity) : null,
mode: params.meta.mode,
runtime_options_json: params.meta.runtimeOptions ? JSON.stringify(params.meta.runtimeOptions) : null,
cwd: params.meta.cwd ?? null,
state: params.meta.state,
last_activity_at: params.meta.lastActivityAt,
last_error: params.meta.lastError ?? null,
updated_at: params.updatedAt
};
}
function selectAcpSessionRow(db, sessionKey) {
return executeSqliteQueryTakeFirstSync(db, getAcpSessionKysely(db).selectFrom("acp_sessions").selectAll().where("session_key", "=", sessionKey));
}
function acpSessionRowMatchesEntry(row, entry) {
return row.session_id == null || row.session_id === entry?.sessionId;
}
function readAcpSessionMeta(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return;
const storeEntry = readSessionEntryFromStore({
sessionKey,
cfg: params.cfg,
env: params.env,
clone: false
});
const row = selectAcpSessionRow(openOpenClawStateDatabase({
env: params.env,
path: params.databasePath
}).db, storeEntry.storeSessionKey);
if (!row || !acpSessionRowMatchesEntry(row, storeEntry.entry)) return;
return rowToAcpSessionMeta(row);
}
function readAcpSessionMetaForEntry(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return;
const row = selectAcpSessionRow(openOpenClawStateDatabase({
env: params.env,
path: params.databasePath
}).db, sessionKey);
if (!row || !acpSessionRowMatchesEntry(row, params.entry)) return;
return rowToAcpSessionMeta(row);
}
function selectAcpSessionRows(options = {}) {
const database = openOpenClawStateDatabase(options);
return executeSqliteQuerySync(database.db, getAcpSessionKysely(database.db).selectFrom("acp_sessions").selectAll().orderBy("last_activity_at", "desc").orderBy("session_key", "asc")).rows;
}
function writeAcpSessionMetaForMigration(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return;
const row = bindAcpSessionMeta({
sessionKey,
sessionId: params.sessionId,
meta: params.meta,
updatedAt: params.now?.() ?? Date.now()
});
runOpenClawStateWriteTransaction((database) => {
upsertAcpSessionMetaRow(database.db, row);
}, {
env: params.env,
path: params.databasePath
});
}
function repairAcpSessionMetaKeyForMigration(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return false;
let repaired = false;
runOpenClawStateWriteTransaction((database) => {
const currentRow = selectAcpSessionRow(database.db, sessionKey);
if (currentRow && acpSessionRowMatchesEntry(currentRow, params.entry)) return;
const normalizedSessionKey = normalizeLowercaseStringOrEmpty(sessionKey);
const candidateKeys = /* @__PURE__ */ new Set();
candidateKeys.add(normalizedSessionKey);
for (const candidate of params.candidateSessionKeys ?? []) {
const trimmed = typeof candidate === "string" ? candidate.trim() : "";
if (trimmed && trimmed !== sessionKey && normalizeLowercaseStringOrEmpty(trimmed) === normalizedSessionKey) candidateKeys.add(trimmed);
}
let row;
for (const candidateKey of candidateKeys) {
const candidateRow = selectAcpSessionRow(database.db, candidateKey);
if (candidateRow && acpSessionRowMatchesEntry(candidateRow, params.entry)) {
row = candidateRow;
break;
}
}
row ??= executeSqliteQuerySync(database.db, getAcpSessionKysely(database.db).selectFrom("acp_sessions").selectAll().where((eb) => eb.fn("lower", ["session_key"]), "=", normalizedSessionKey).orderBy("last_activity_at", "desc").orderBy("session_key", "asc")).rows.find((candidate) => candidate.session_key !== sessionKey && acpSessionRowMatchesEntry(candidate, params.entry));
if (!row) return;
upsertAcpSessionMetaRow(database.db, {
...row,
session_key: sessionKey,
updated_at: params.now?.() ?? Date.now()
});
executeSqliteQuerySync(database.db, getAcpSessionKysely(database.db).deleteFrom("acp_sessions").where("session_key", "=", row.session_key));
repaired = true;
}, {
env: params.env,
path: params.databasePath
});
return repaired;
}
function upsertAcpSessionMetaRow(db, row) {
executeSqliteQuerySync(db, getAcpSessionKysely(db).insertInto("acp_sessions").values(row).onConflict((conflict) => conflict.column("session_key").doUpdateSet({
session_id: (eb) => eb.ref("excluded.session_id"),
backend: (eb) => eb.ref("excluded.backend"),
agent: (eb) => eb.ref("excluded.agent"),
runtime_session_name: (eb) => eb.ref("excluded.runtime_session_name"),
identity_json: (eb) => eb.ref("excluded.identity_json"),
mode: (eb) => eb.ref("excluded.mode"),
runtime_options_json: (eb) => eb.ref("excluded.runtime_options_json"),
cwd: (eb) => eb.ref("excluded.cwd"),
state: (eb) => eb.ref("excluded.state"),
last_activity_at: (eb) => eb.ref("excluded.last_activity_at"),
last_error: (eb) => eb.ref("excluded.last_error"),
updated_at: (eb) => eb.ref("excluded.updated_at")
})));
}
function readSessionEntryFromStore(params) {
const { cfg, storePath } = resolveSessionStorePathForAcp({
sessionKey: params.sessionKey,
cfg: params.cfg,
env: params.env
});
try {
const store = loadSessionStore(storePath, params.clone === false ? { clone: false } : void 0);
const storeSessionKey = resolveStoreSessionKey(store, params.sessionKey);
return {
cfg,
storePath,
storeSessionKey,
entry: store[storeSessionKey]
};
} catch {
return {
cfg,
storePath,
storeSessionKey: normalizeLowercaseStringOrEmpty(params.sessionKey),
storeReadFailed: true
};
}
}
function readAcpSessionEntry(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return null;
const storeEntry = readSessionEntryFromStore(params);
const row = selectAcpSessionRow(openOpenClawStateDatabase({
env: params.env,
path: params.databasePath
}).db, storeEntry.storeSessionKey);
const acp = row && acpSessionRowMatchesEntry(row, storeEntry.entry) ? rowToAcpSessionMeta(row) : void 0;
return {
cfg: storeEntry.cfg,
storePath: storeEntry.storePath,
sessionKey,
storeSessionKey: storeEntry.storeSessionKey,
entry: storeEntry.entry,
acp,
storeReadFailed: storeEntry.storeReadFailed
};
}
async function listAcpSessionEntries(params) {
const cfg = params.cfg ?? getRuntimeConfig();
const rows = selectAcpSessionRows({
env: params.env,
path: params.databasePath
});
const entries = [];
for (const row of rows) {
const sessionKey = row.session_key;
const { storePath } = resolveSessionStorePathForAcp({
sessionKey,
cfg,
env: params.env
});
let store;
try {
store = loadSessionStore(storePath, params.clone === false ? { clone: false } : void 0);
} catch {
continue;
}
const storeSessionKey = resolveStoreSessionKey(store, sessionKey);
const entry = store[storeSessionKey];
if (!entry || !acpSessionRowMatchesEntry(row, entry)) continue;
entries.push({
cfg,
storePath,
sessionKey,
storeSessionKey,
entry,
acp: rowToAcpSessionMeta(row)
});
}
return entries;
}
function mergeAcpForReturn(entry, acp) {
return mergeSessionEntry(entry, { acp });
}
function sessionStoreUpdateOptions(params) {
return {
activeSessionKey: normalizeLowercaseStringOrEmpty(params.sessionKey),
...params.skipMaintenance === true ? { skipMaintenance: true } : {},
...params.takeCacheOwnership === true ? { takeCacheOwnership: true } : {}
};
}
async function upsertAcpSessionMeta(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return null;
const storeEntry = readSessionEntryFromStore({
sessionKey,
cfg: params.cfg,
env: params.env,
clone: false
});
const { entry } = storeEntry;
const storageSessionKey = storeEntry.storeSessionKey;
let current;
let nextMeta;
let preparedEntry;
const updatedAt = params.now?.() ?? Date.now();
runOpenClawStateWriteTransaction((database) => {
const currentRow = selectAcpSessionRow(database.db, storageSessionKey);
current = currentRow && acpSessionRowMatchesEntry(currentRow, entry) ? rowToAcpSessionMeta(currentRow) : void 0;
preparedEntry = mergeSessionEntry(entry, { updatedAt });
nextMeta = params.mutate(current, current ? mergeAcpForReturn(preparedEntry, current) : entry);
if (nextMeta === null) {
executeSqliteQuerySync(database.db, getAcpSessionKysely(database.db).deleteFrom("acp_sessions").where("session_key", "=", storageSessionKey));
return;
}
if (nextMeta !== void 0) upsertAcpSessionMetaRow(database.db, bindAcpSessionMeta({
sessionKey: storageSessionKey,
sessionId: preparedEntry.sessionId,
meta: nextMeta,
updatedAt
}));
}, {
env: params.env,
path: params.databasePath
});
if (nextMeta === void 0) return current ? mergeAcpForReturn(entry, current) : entry ?? null;
if (nextMeta === null) {
if (!entry) return null;
const { updateSessionStore } = await loadSessionStoreRuntime();
return await updateSessionStore(storeEntry.storePath, (store) => {
const storeSessionKey = resolveStoreSessionKey(store, storageSessionKey);
const next = { ...store[storeSessionKey] ?? entry };
delete next.acp;
store[storeSessionKey] = next;
return next;
}, sessionStoreUpdateOptions({
...params,
sessionKey: storageSessionKey
}));
}
const { updateSessionStore } = await loadSessionStoreRuntime();
return mergeAcpForReturn(await updateSessionStore(storeEntry.storePath, (store) => {
const storeSessionKey = resolveStoreSessionKey(store, storageSessionKey);
const next = mergeSessionEntry(store[storeSessionKey], {
sessionId: preparedEntry?.sessionId,
updatedAt
});
delete next.acp;
store[storeSessionKey] = next;
return next;
}, sessionStoreUpdateOptions({
...params,
sessionKey: storageSessionKey
})), nextMeta);
}
//#endregion
export { repairAcpSessionMetaKeyForMigration as a, readAcpSessionMetaForEntry as i, readAcpSessionEntry as n, upsertAcpSessionMeta as o, readAcpSessionMeta as r, writeAcpSessionMetaForMigration as s, listAcpSessionEntries as t };