UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

208 lines (207 loc) 8.79 kB
import { i as asOptionalObjectRecord } from "./record-coerce-DItp3I4t.js"; import { h as clearNodeSqliteKyselyCacheForDatabase, t as openNodeSqliteDatabase, u as runSqliteImmediateTransactionSync } from "./node-sqlite-BpQX3W0e.js"; import { a as getNodeSqliteKysely, r as executeSqliteQuerySync } from "./kysely-sync-COmh4HWh.js"; import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js"; import { Xn as validateProgressCardGetParams, Zn as validateProgressCardPutParams } from "./src-BiL5aQto.js"; import { d as errorShape } from "./error-codes-Bo8q2D1o.js"; import { A as ensureOpenClawAgentProgressCardSchemaInTransaction } from "./openclaw-agent-db-maintenance-wTIy-jt-.js"; import { g as runOpenClawAgentWriteTransaction } from "./openclaw-agent-db-CWtDoRbC.js"; import { n as withOpenClawAgentDatabaseReadOnly } from "./openclaw-agent-db-readonly-CHjf8FxN.js"; import { i as resolveSessionStoreKey } from "./session-store-key-8xEjWSNi.js"; import { n as resolveRequestedSessionAgentId } from "./session-request-agent-CCRSEGCB.js"; import { n as normalizeProgressCardInput, t as ProgressCardInputError } from "./progress-card-input-Dh1ZuLLZ.js"; import { t as assertValidParams } from "./validation-pzrlzFvo.js"; import { n as resolveGatewaySessionDatabase } from "./board-store-C0cfYoGS.js"; import { m as sessionObserverScopeKey } from "./session-observer-model-D5MYTAfa.js"; import fs from "node:fs"; //#region src/session-cards/progress-card-store.ts function withProgressCardDatabase(input, readOnly, operation) { if (typeof input !== "string") return operation(input, "openclaw-agent.sqlite"); const db = openNodeSqliteDatabase(input, { readOnly }); try { if (!readOnly) db.exec("PRAGMA foreign_keys = ON;"); return operation(db, input); } finally { clearNodeSqliteKyselyCacheForDatabase(db); db.close(); } } function progressCardTablePresent(db) { return Boolean(db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'session_progress_cards'").get()); } function selectProgressCard(db, sessionKey) { const kysely = getNodeSqliteKysely(db); return executeSqliteQuerySync(db, kysely.selectFrom("session_progress_cards").select([ "session_key", "markdown", "steps_json", "revision", "created_at", "updated_at" ]).where("session_key", "=", sessionKey).limit(1)).rows[0] ?? null; } function rowToProgressCard(row) { const steps = row.steps_json ? readStoredSteps(row.steps_json) : void 0; if (!row.markdown && !steps?.length) return null; return { sessionKey: row.session_key, revision: row.revision, updatedAt: row.updated_at, ...row.markdown ? { markdown: row.markdown } : {}, ...steps && steps.length > 0 ? { steps } : {} }; } function readStoredSteps(value) { const parsed = JSON.parse(value); if (!Array.isArray(parsed)) throw new Error("stored progress-card steps are not an array"); return parsed.map((entry, index) => { const record = asOptionalObjectRecord(entry); if (!record) throw new Error(`stored progress-card step ${index} is invalid`); const { step, status } = record; if (typeof step !== "string" || status !== "pending" && status !== "in_progress" && status !== "completed") throw new Error(`stored progress-card step ${index} is invalid`); return { step, status }; }); } function readSessionProgressCard(dbPathOrDb, sessionKey) { if (typeof dbPathOrDb === "string" && !fs.existsSync(dbPathOrDb)) return null; return withProgressCardDatabase(dbPathOrDb, true, (db) => { if (!progressCardTablePresent(db)) return null; const row = selectProgressCard(db, sessionKey); return row ? rowToProgressCard(row) : null; }); } function writeSessionProgressCard(dbPathOrDb, sessionKey, input) { return withProgressCardDatabase(dbPathOrDb, false, (db, label) => { const write = () => { ensureOpenClawAgentProgressCardSchemaInTransaction(db); const kysely = getNodeSqliteKysely(db); const markdown = input.markdown?.trim() ? input.markdown : void 0; const steps = input.steps && input.steps.length > 0 ? input.steps : void 0; if (!markdown && !steps) { const previous = selectProgressCard(db, sessionKey); if (input.expectedRevision !== void 0) { const current = previous ? rowToProgressCard(previous) : null; if (!previous || previous.revision !== input.expectedRevision || !current?.steps?.length || current.steps.some((step) => step.status !== "completed")) return { card: current }; } if (previous) executeSqliteQuerySync(db, kysely.updateTable("session_progress_cards").set({ markdown: null, steps_json: null, revision: previous.revision + 1, updated_at: Date.now() }).where("session_key", "=", sessionKey)); return { cleared: true }; } const previous = selectProgressCard(db, sessionKey); const now = Date.now(); const revision = (previous?.revision ?? 0) + 1; const stepsJson = steps ? JSON.stringify(steps) : null; executeSqliteQuerySync(db, kysely.insertInto("session_progress_cards").values({ session_key: sessionKey, markdown: markdown ?? null, steps_json: stepsJson, revision, created_at: previous?.created_at ?? now, updated_at: now }).onConflict((conflict) => conflict.column("session_key").doUpdateSet({ markdown: markdown ?? null, steps_json: stepsJson, revision, updated_at: now }))); return { card: { sessionKey, revision, updatedAt: now, ...markdown ? { markdown } : {}, ...steps ? { steps } : {} } }; }; return db.isTransaction ? write() : runSqliteImmediateTransactionSync(db, write, { databaseLabel: label, operationLabel: "progress-card.write" }); }); } //#endregion //#region src/gateway/progress-card-store.ts const progressCardStore = { get(sessionKey) { const resolved = resolveGatewaySessionDatabase(sessionKey); const result = withOpenClawAgentDatabaseReadOnly((database) => readSessionProgressCard(database.db, resolved.sessionKey), resolved); return result.found ? result.value : null; }, put(sessionKey, input) { const resolved = resolveGatewaySessionDatabase(sessionKey); const result = runOpenClawAgentWriteTransaction((transactionDatabase) => writeSessionProgressCard(transactionDatabase.db, resolved.sessionKey, input), resolved, { operationLabel: "progress-card.put" }); return "card" in result ? result : { card: null }; } }; //#endregion //#region src/gateway/server-methods/progress-card.ts function resolveProgressCardSessionKey(sessionKey, context, respond) { const cfg = context.getRuntimeConfig(); const requested = resolveRequestedSessionAgentId(cfg, sessionKey, void 0); if (!requested.ok) { respond(false, void 0, requested.error); return; } const canonicalKey = resolveSessionStoreKey({ cfg, sessionKey, storeAgentId: requested.agentId }); return sessionObserverScopeKey(canonicalKey, requested.agentId); } function createProgressCardHandlers(store = progressCardStore) { return { "progressCard.get": ({ params, respond, context }) => { if (!assertValidParams(params, validateProgressCardGetParams, "progressCard.get", respond)) return; const sessionKey = resolveProgressCardSessionKey(params.sessionKey, context, respond); if (!sessionKey) return; try { respond(true, { card: store.get(sessionKey) }, void 0); } catch (error) { respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error))); } }, "progressCard.put": ({ params, respond, context }) => { if (!assertValidParams(params, validateProgressCardPutParams, "progressCard.put", respond)) return; let input; try { input = normalizeProgressCardInput({ markdown: params.markdown, plan: params.plan }); } catch (error) { if (!(error instanceof ProgressCardInputError)) throw error; respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, error.message)); return; } if (params.expectedRevision !== void 0 && (input.markdown || input.steps?.length)) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "expectedRevision is only valid when clearing a card")); return; } const sessionKey = resolveProgressCardSessionKey(params.sessionKey, context, respond); if (!sessionKey) return; try { const result = store.put(sessionKey, { ...input, expectedRevision: params.expectedRevision }); if (params.expectedRevision === void 0 || result.card === null) context.broadcast("progressCard.changed", { sessionKey, revision: result.card?.revision ?? null }); respond(true, result, void 0); } catch (error) { respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error))); } } }; } const progressCardHandlers = createProgressCardHandlers(); //#endregion export { progressCardHandlers };