UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

189 lines (188 loc) 7.85 kB
import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js"; import { E as hasSessionAutoModelFallbackProvenance, j as resolveSessionAuthProfileOverrideSource } from "./agent-scope-DbtJyKUL.js"; import "./session-accessor-YsytfDtG.js"; import { l as loadSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js"; import { i as preserveCreationStamp } from "./session-entry-provenance-jzrCUpdQ.js"; import { t as listSessionEntriesCore } from "./session-accessor.entry-CQ2WPpfn.js"; import { t as clearAllCliSessions } from "./cli-session-binding-Aa6nlDa8.js"; import { d as resolveSessionLifecycleTimestamps, f as resolveSessionWorkStartError } from "./lifecycle-BaroCBMc.js"; import { n as resolveSessionResetPolicy, t as evaluateSessionFreshness } from "./reset-policy-Bcf937ne.js"; import { t as hasProviderOwnedSession } from "./entry-freshness-C81RWf2e.js"; import { r as clearBootstrapSnapshotOnSessionRollover } from "./bootstrap-cache-Bpsy6pH_.js"; import "./cli-session-pAa_-y_N.js"; import crypto from "node:crypto"; //#region src/cron/isolated-agent/session.ts /** Resolves session rollover and carried state for isolated cron runs. */ const FRESH_CRON_CARRIED_PREFERENCE_FIELDS = [ "chatType", "thinkingLevel", "fastMode", "verboseLevel", "traceLevel", "reasoningLevel", "ttsAuto", "responseUsage", "pinnedAt", "label", "displayName" ]; const AMBIENT_SESSION_CONTEXT_FIELDS = [ "elevatedLevel", "groupActivation", "groupActivationNeedsSystemIntro", "sendPolicy", "queueMode", "queueDebounceMs", "queueCap", "queueDrop", "groupId", "subject", "groupChannel", "space", "acp" ]; function cloneSessionField(value) { return globalThis.structuredClone(value); } function copySessionFields(target, entry, fields) { for (const field of fields) if (entry[field] !== void 0) target[field] = cloneSessionField(entry[field]); } function preserveNonAutoModelOverride(target, entry) { const recoveredAutoFallbackOverride = entry.modelOverrideSource === void 0 && hasSessionAutoModelFallbackProvenance(entry); if (entry.modelOverrideSource !== "auto" && !recoveredAutoFallbackOverride) { let preservedModelSelection = false; if (entry.modelOverride !== void 0) { target.modelOverride = entry.modelOverride; preservedModelSelection = true; } if (entry.providerOverride !== void 0) target.providerOverride = entry.providerOverride; if (entry.modelOverrideSource !== void 0) target.modelOverrideSource = entry.modelOverrideSource; if (entry.modelOverrideRouteResolution !== void 0) target.modelOverrideRouteResolution = entry.modelOverrideRouteResolution; if (preservedModelSelection && entry.agentRuntimeOverride !== void 0) target.agentRuntimeOverride = entry.agentRuntimeOverride; } } function preserveUserAuthOverride(target, entry) { const source = resolveSessionAuthProfileOverrideSource(entry); if (source === "user") { if (entry.authProfileOverride !== void 0) target.authProfileOverride = entry.authProfileOverride; target.authProfileOverrideSource = source; if (entry.authProfileOverrideCompactionCount !== void 0) target.authProfileOverrideCompactionCount = entry.authProfileOverrideCompactionCount; } } function sanitizeFreshCronSessionEntry(entry, options) { const next = {}; copySessionFields(next, entry, FRESH_CRON_CARRIED_PREFERENCE_FIELDS); if (entry.skillLibrarySelections) next.skillLibrarySelections = entry.skillLibrarySelections.map((selection) => ({ ...selection })); if (options.preserveAmbientContext) copySessionFields(next, entry, AMBIENT_SESSION_CONTEXT_FIELDS); preserveNonAutoModelOverride(next, entry); preserveUserAuthOverride(next, entry); return next; } /** * Reads the current cron session row without an in-process cache snapshot. * Lifecycle admission guards compare this against the run's initial entry, so * the read must bypass cached store snapshots (accessor readConsistency * "latest"). Cron keys are canonicalized before use, so accessor key * resolution selects the same row the cron persist path writes. */ function loadCronSessionEntryLatest(storePath, sessionKey) { return loadSessionEntry({ sessionKey, storePath, readConsistency: "latest" }); } /** Resolves or rolls over the cron session entry for one isolated-agent run. */ function resolveCronSession(params) { const sessionCfg = params.cfg.session; const storePath = resolveSessionStorePathCore(sessionCfg?.store, { agentId: params.agentId }); const store = params.store ?? Object.fromEntries(listSessionEntriesCore({ agentId: params.agentId, storePath }).map(({ sessionKey, entry }) => [sessionKey, entry])); const sourceSessionKey = params.sourceSessionKey?.trim(); const sourceSessionDiffers = Boolean(sourceSessionKey && sourceSessionKey !== params.sessionKey); const targetEntry = store[params.sessionKey]; const entry = store[sourceSessionKey || params.sessionKey]; const canRollArchivedHeartbeat = params.forceNew === true && targetEntry?.archivedAt !== void 0 && targetEntry.initializationPending !== true && Boolean(targetEntry.heartbeatIsolatedBaseSessionKey?.trim()); const sessionWorkStartError = resolveSessionWorkStartError(params.sessionKey, targetEntry); if (sessionWorkStartError && !canRollArchivedHeartbeat) throw new Error(sessionWorkStartError); let sessionId; let isNewSession; let systemSent; let resetBoundaryPending; if (!params.forceNew && entry?.sessionId) { const resetPolicy = resolveSessionResetPolicy({ sessionCfg, resetType: "direct" }); if ((resetPolicy.configured !== true && hasProviderOwnedSession(entry) ? { fresh: true } : evaluateSessionFreshness({ updatedAt: entry.updatedAt, ...resolveSessionLifecycleTimestamps({ entry, agentId: params.agentId, sessionKey: params.sessionKey, storePath }), now: params.nowMs, policy: resetPolicy })).fresh) { sessionId = entry.sessionId; isNewSession = false; systemSent = entry.systemSent ?? false; } else { sessionId = sourceSessionDiffers ? crypto.randomUUID() : entry.sessionId; isNewSession = true; systemSent = false; if (!sourceSessionDiffers) resetBoundaryPending = { reason: "cron-stale", sessionFile: params.sessionKey }; } } else { sessionId = crypto.randomUUID(); isNewSession = true; systemSent = false; } const previousSessionId = isNewSession && !sourceSessionDiffers && !resetBoundaryPending ? entry?.sessionId : void 0; clearBootstrapSnapshotOnSessionRollover({ sessionKey: params.sessionKey, previousSessionId }); const baseEntry = entry ? isNewSession ? sanitizeFreshCronSessionEntry(entry, { preserveAmbientContext: !params.forceNew }) : entry : void 0; const lifecycleRevision = crypto.randomUUID(); const sessionEntry = { ...baseEntry, skillLibrarySelections: structuredClone(targetEntry?.skillLibrarySelections ?? params.skillLibrarySelections ?? baseEntry?.skillLibrarySelections), sessionId, lifecycleRevision, updatedAt: params.nowMs, sessionStartedAt: isNewSession ? params.nowMs : baseEntry?.sessionStartedAt ?? resolveSessionLifecycleTimestamps({ entry, agentId: params.agentId, sessionKey: params.sessionKey, storePath }).sessionStartedAt, lastInteractionAt: isNewSession ? params.nowMs : baseEntry?.lastInteractionAt, ...params.hookExternalContentSource ? { hookExternalContentSource: params.hookExternalContentSource } : {}, systemSent }; if (resetBoundaryPending) { clearAllCliSessions(sessionEntry); sessionEntry.agentHarnessId = void 0; sessionEntry.compactionCount = 0; } return { storePath, store, sessionEntry: preserveCreationStamp(sessionEntry, targetEntry), lifecycleRevision, systemSent, isNewSession, previousSessionId, resetBoundaryPending, initialSessionEntry: targetEntry }; } //#endregion export { resolveCronSession as n, loadCronSessionEntryLatest as t };