UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

340 lines (339 loc) 12.8 kB
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 };