UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

279 lines (278 loc) 12.5 kB
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js"; import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js"; import { f as resolveAgentIdFromSessionKey } from "./session-key-B_NoIfpX.js"; import "./defaults-mDjiWzE5.js"; import { a as resolveSessionFilePathOptions, i as resolveSessionFilePath } from "./paths-NEwU8m3X.js"; import { D as resolveMaintenanceConfigFromInput } from "./store-load-C4uq6Lrq.js"; import { d as updateSessionStore } from "./store-Qsgtu-0y.js"; import { d as setSessionRuntimeModel, f as canonicalizeAbsoluteSessionFilePath, p as rewriteSessionFileForNewSessionId, r as mergeSessionEntry } from "./types-D8S_uNvu.js"; import "./sessions-D6zZvoxX.js"; import { h as isCliProvider } from "./model-selection-CA_65iXi.js"; import { i as hasNonzeroUsage, r as deriveSessionTotalTokens } from "./usage-C67Kbb7n.js"; import { c as setCliSessionId, n as clearCliSession, s as setCliSessionBinding } from "./cli-session-DY8dQzGa.js"; import path from "node:path"; //#region src/agents/command/session-store.ts /** * Updates persisted session metadata after agent command runs. */ const usageFormatModuleLoader = createLazyImportLoader(() => import("./usage-format-CCb6QRAg.js")); const contextModuleLoader = createLazyImportLoader(() => import("./context-C0bALrvk.js")); async function getUsageFormatModule() { return await usageFormatModuleLoader.load(); } async function getContextModule() { return await contextModuleLoader.load(); } function resolveNonNegativeNumber(value) { return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0; } function resolvePositiveInteger(value) { if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return; return Math.floor(value); } function removeLifecycleStateFromMetadataPatch(entry) { const next = { ...entry }; delete next.status; delete next.startedAt; delete next.endedAt; delete next.runtimeMs; return next; } /** Applies run result metadata, usage, and CLI bindings to a session entry. */ async function updateSessionStoreAfterAgentRun(params) { const { cfg, sessionId, sessionKey, storePath, sessionStore, defaultProvider, defaultModel, fallbackProvider, fallbackModel, result } = params; const now = Date.now(); const touchInteraction = params.touchInteraction !== false; const usage = result.meta.agentMeta?.usage; const promptTokens = result.meta.agentMeta?.promptTokens; const lastCallUsage = result.meta.agentMeta?.lastCallUsage; const compactionTokensAfter = typeof result.meta.agentMeta?.compactionTokensAfter === "number" && Number.isFinite(result.meta.agentMeta.compactionTokensAfter) && result.meta.agentMeta.compactionTokensAfter >= 0 ? Math.floor(result.meta.agentMeta.compactionTokensAfter) : void 0; const compactionsThisRun = Math.max(0, result.meta.agentMeta?.compactionCount ?? 0); const modelUsed = result.meta.agentMeta?.model ?? fallbackModel ?? defaultModel; const providerUsed = result.meta.agentMeta?.provider ?? fallbackProvider ?? defaultProvider; const agentHarnessId = normalizeOptionalString(result.meta.agentMeta?.agentHarnessId); const activeSessionFile = normalizeOptionalString(result.meta.agentMeta?.sessionFile); const runtimeContextTokens = resolvePositiveInteger(result.meta.agentMeta?.contextTokens); const contextBudgetStatus = result.meta.agentMeta?.contextBudgetStatus; const contextTokens = runtimeContextTokens !== void 0 ? runtimeContextTokens : typeof params.contextTokensOverride === "number" && params.contextTokensOverride > 0 ? params.contextTokensOverride : (await getContextModule()).resolveContextTokensForModel({ cfg, provider: providerUsed, model: modelUsed, fallbackContextTokens: 2e5, allowAsyncLoad: false }) ?? 2e5; const preserveUserFacingRunState = params.preserveUserFacingSessionModelState === true; const preserveRuntimeModel = params.preserveRuntimeModel === true || preserveUserFacingRunState; const entry = sessionStore[sessionKey] ?? { sessionId, updatedAt: now, sessionStartedAt: now }; const next = { ...entry, sessionId, updatedAt: now, sessionStartedAt: entry.sessionId === sessionId ? entry.sessionStartedAt ?? now : now, lastInteractionAt: touchInteraction ? now : entry.lastInteractionAt, ...preserveRuntimeModel ? {} : { contextTokens } }; if (entry.sessionId !== sessionId) { next.sessionFile = activeSessionFile ?? resolveCompactionSessionFile({ entry, sessionKey, storePath, newSessionId: sessionId }); next.usageFamilyKey = entry.usageFamilyKey ?? sessionKey; next.usageFamilySessionIds = Array.from(new Set([ ...entry.usageFamilySessionIds ?? [], entry.sessionId, sessionId ])); } else if (activeSessionFile) next.sessionFile = activeSessionFile; if (preserveRuntimeModel) { if (entry.model) { next.contextTokens = entry.contextTokens; if (entry.modelProvider) setSessionRuntimeModel(next, { provider: entry.modelProvider, model: entry.model }); else next.model = entry.model; } } else setSessionRuntimeModel(next, { provider: providerUsed, model: modelUsed }); if (!preserveUserFacingRunState) { if (agentHarnessId) next.agentHarnessId = agentHarnessId; else if (result.meta.executionTrace?.runner === "cli") next.agentHarnessId = void 0; if (isCliProvider(providerUsed, cfg)) { const cliSessionBinding = result.meta.agentMeta?.cliSessionBinding; if (result.meta.agentMeta?.clearCliSessionBinding === true) clearCliSession(next, providerUsed); else if (cliSessionBinding?.sessionId?.trim()) setCliSessionBinding(next, providerUsed, cliSessionBinding); else { const cliSessionId = result.meta.agentMeta?.sessionId?.trim(); if (cliSessionId) setCliSessionId(next, providerUsed, cliSessionId); } } next.abortedLastRun = result.meta.aborted ?? false; if (result.meta.systemPromptReport) next.systemPromptReport = result.meta.systemPromptReport; if (!preserveRuntimeModel) next.contextBudgetStatus = contextBudgetStatus; } if (hasNonzeroUsage(usage) && !preserveUserFacingRunState) { const { estimateUsageCost, resolveModelCostConfig } = await getUsageFormatModule(); const input = usage.input ?? 0; const output = usage.output ?? 0; const usageForContext = isCliProvider(providerUsed, cfg) ? promptTokens ? void 0 : lastCallUsage : usage; const totalTokens = deriveSessionTotalTokens({ usage: promptTokens ? void 0 : usageForContext, contextTokens, promptTokens }); const runEstimatedCostUsd = resolveNonNegativeNumber(estimateUsageCost({ usage, cost: resolveModelCostConfig({ provider: providerUsed, model: modelUsed, config: cfg }) })); next.inputTokens = input; next.outputTokens = output; const hasUsageTotalTokens = typeof totalTokens === "number" && Number.isFinite(totalTokens) && totalTokens > 0; const useCompactionSnapshot = compactionTokensAfter !== void 0 && !hasUsageTotalTokens; if (useCompactionSnapshot) { next.totalTokens = compactionTokensAfter; next.totalTokensFresh = true; next.inputTokens = void 0; next.outputTokens = void 0; next.cacheRead = void 0; next.cacheWrite = void 0; next.contextBudgetStatus = void 0; } else if (hasUsageTotalTokens) { next.totalTokens = totalTokens; next.totalTokensFresh = true; } else { next.totalTokens = void 0; next.totalTokensFresh = false; } if (!useCompactionSnapshot) { next.cacheRead = usage.cacheRead ?? 0; next.cacheWrite = usage.cacheWrite ?? 0; } if (runEstimatedCostUsd !== void 0) next.estimatedCostUsd = runEstimatedCostUsd; } else if (compactionTokensAfter !== void 0 && !preserveUserFacingRunState) { next.totalTokens = compactionTokensAfter; next.totalTokensFresh = true; next.inputTokens = void 0; next.outputTokens = void 0; next.cacheRead = void 0; next.cacheWrite = void 0; next.contextBudgetStatus = void 0; } else if (!preserveUserFacingRunState && typeof entry.totalTokens === "number" && Number.isFinite(entry.totalTokens) && entry.totalTokens > 0) { next.totalTokens = entry.totalTokens; next.totalTokensFresh = false; } if (compactionsThisRun > 0 && !preserveUserFacingRunState) next.compactionCount = (entry.compactionCount ?? 0) + compactionsThisRun; const metadataPatch = preserveUserFacingRunState ? { updatedAt: next.updatedAt, ...touchInteraction ? { lastInteractionAt: next.lastInteractionAt } : {} } : removeLifecycleStateFromMetadataPatch(next); const persisted = await updateSessionStore(storePath, (store) => { if (preserveUserFacingRunState && !store[sessionKey]) return; const merged = mergeSessionEntry(store[sessionKey], metadataPatch); store[sessionKey] = merged; return merged; }, { takeCacheOwnership: true, maintenanceConfig: resolveMaintenanceConfigFromInput(cfg.session?.maintenance), resolveSingleEntryPersistence: (entryLocal) => entryLocal ? { sessionKey, entry: entryLocal } : void 0 }); if (persisted) sessionStore[sessionKey] = persisted; } /** Clears a stored CLI session binding after a failed or invalidated run. */ async function clearCliSessionInStore(params) { const { provider, sessionKey, sessionStore, storePath } = params; const entry = sessionStore[sessionKey]; if (!entry) return; const next = { ...entry }; clearCliSession(next, provider); next.updatedAt = Date.now(); const persisted = await updateSessionStore(storePath, (store) => { const merged = mergeSessionEntry(store[sessionKey], next); store[sessionKey] = merged; return merged; }); sessionStore[sessionKey] = persisted; return persisted; } /** Records CLI compaction metadata on the persisted session entry. */ async function recordCliCompactionInStore(params) { const { provider, sessionKey, sessionStore, storePath } = params; const entry = sessionStore[sessionKey]; if (!entry) return; const next = { ...entry }; clearCliSession(next, provider); next.compactionCount = (entry.compactionCount ?? 0) + 1; next.updatedAt = Date.now(); const newSessionId = normalizeOptionalString(params.newSessionId); const explicitNewSessionFile = normalizeOptionalString(params.newSessionFile); const sessionIdChanged = Boolean(newSessionId && newSessionId !== entry.sessionId); const sessionFileChanged = Boolean(explicitNewSessionFile && explicitNewSessionFile !== entry.sessionFile); if (sessionIdChanged && newSessionId) { next.sessionId = newSessionId; next.sessionFile = explicitNewSessionFile ?? resolveCompactionSessionFile({ entry, sessionKey, storePath, newSessionId }); next.usageFamilyKey = entry.usageFamilyKey ?? sessionKey; next.usageFamilySessionIds = Array.from(new Set([ ...entry.usageFamilySessionIds ?? [], entry.sessionId, newSessionId ])); } else if (sessionFileChanged && explicitNewSessionFile) next.sessionFile = explicitNewSessionFile; const tokensAfterCompaction = resolveNonNegativeNumber(params.tokensAfter); next.contextBudgetStatus = void 0; if (tokensAfterCompaction !== void 0) { next.totalTokens = Math.floor(tokensAfterCompaction); next.totalTokensFresh = true; next.inputTokens = void 0; next.outputTokens = void 0; next.cacheRead = void 0; next.cacheWrite = void 0; } else { next.totalTokensFresh = false; next.inputTokens = void 0; next.outputTokens = void 0; next.cacheRead = void 0; next.cacheWrite = void 0; } const persisted = await updateSessionStore(storePath, (store) => { const merged = mergeSessionEntry(store[sessionKey], next); store[sessionKey] = merged; return merged; }); sessionStore[sessionKey] = persisted; return persisted; } function resolveCompactionSessionFile(params) { const pathOpts = resolveSessionFilePathOptions({ agentId: resolveAgentIdFromSessionKey(params.sessionKey), storePath: params.storePath }); const rewrittenSessionFile = rewriteSessionFileForNewSessionId({ sessionFile: params.entry.sessionFile, previousSessionId: params.entry.sessionId, nextSessionId: params.newSessionId }); const normalizedRewrittenSessionFile = rewrittenSessionFile && path.isAbsolute(rewrittenSessionFile) ? canonicalizeAbsoluteSessionFilePath(rewrittenSessionFile) : rewrittenSessionFile; return resolveSessionFilePath(params.newSessionId, normalizedRewrittenSessionFile ? { sessionFile: normalizedRewrittenSessionFile } : void 0, pathOpts); } //#endregion export { recordCliCompactionInStore as n, updateSessionStoreAfterAgentRun as r, clearCliSessionInStore as t };