UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

103 lines (102 loc) • 4.45 kB
import { o as resolveFreshSessionTotalTokens } from "./types-BGDhC4_W.mjs"; import crypto from "node:crypto"; //#region src/config/sessions/goals-transitions.ts var SessionGoalTransitionError = class extends Error { constructor(..._args) { super(..._args); this.name = "SessionGoalTransitionError"; } }; function normalizeTokenCount(value) { return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0; } function resolveEntryFreshTotalTokens(entry) { return normalizeTokenCount(resolveFreshSessionTotalTokens(entry)); } function normalizeTokenBudget(value) { const normalized = normalizeTokenCount(value); return normalized && normalized > 0 ? normalized : void 0; } function accountSessionGoalUsage(entry, now, options) { const goal = entry.goal; if (!goal) return; const totalTokens = resolveEntryFreshTotalTokens(entry); const hasFreshStart = goal.tokenStartFresh !== false; const shouldHoldStaleStart = !hasFreshStart && options?.adoptFreshBaseline === false; const shouldAdoptFreshStart = !shouldHoldStaleStart && totalTokens !== void 0 && !hasFreshStart; const tokenStart = shouldAdoptFreshStart ? totalTokens : normalizeTokenCount(goal.tokenStart) ?? totalTokens ?? 0; const tokensUsed = totalTokens === void 0 || shouldAdoptFreshStart || shouldHoldStaleStart ? goal.tokensUsed : Math.max(goal.tokensUsed, Math.max(0, totalTokens - tokenStart)); const next = { ...goal, tokenStart, tokenStartFresh: hasFreshStart || shouldAdoptFreshStart, tokensUsed }; if (next.status === "active" && next.tokenBudget !== void 0 && tokensUsed >= next.tokenBudget) { next.status = "budget_limited"; next.budgetLimitedAt = now; next.updatedAt = now; } return next; } function buildCreatedSessionGoal(entry, options, now) { const objective = options.objective; if (!objective.trim()) throw new SessionGoalTransitionError("objective required"); if (entry.goal) throw new SessionGoalTransitionError("goal already exists"); const tokenBudget = normalizeTokenBudget(options.tokenBudget); const tokenStart = resolveEntryFreshTotalTokens(entry); return { schemaVersion: 1, id: crypto.randomUUID(), objective, status: "active", createdAt: now, updatedAt: now, tokenStart: tokenStart ?? 0, tokenStartFresh: tokenStart !== void 0, tokensUsed: 0, ...tokenBudget ? { tokenBudget } : {}, continuationTurns: 0 }; } function buildUpdatedSessionGoalStatus(entry, options, now) { const accounted = accountSessionGoalUsage(entry, now); if (!accounted) throw new SessionGoalTransitionError("goal not found"); if (accounted.status === "complete" && accounted.status !== options.status) throw new SessionGoalTransitionError(`goal is already ${accounted.status}`); const resetsBudgetWindow = options.status === "active" && (accounted.status === "budget_limited" || accounted.status === "usage_limited" || accounted.tokenBudget !== void 0 && accounted.tokensUsed >= accounted.tokenBudget); const freshTokenStart = resetsBudgetWindow ? resolveEntryFreshTotalTokens(entry) : void 0; const next = { ...accounted, status: options.status, updatedAt: now, ...options.note ? { lastStatusNote: options.note } : {}, ...options.status === "paused" ? { pausedAt: now } : {}, ...options.status === "blocked" ? { blockedAt: now } : {}, ...options.status === "complete" ? { completedAt: accounted.completedAt ?? now } : {} }; if (resetsBudgetWindow) { next.tokenStart = freshTokenStart ?? 0; next.tokenStartFresh = freshTokenStart !== void 0; next.tokensUsed = 0; delete next.budgetLimitedAt; delete next.usageLimitedAt; } if (next.status === "active" && next.tokenBudget !== void 0 && next.tokensUsed >= next.tokenBudget) { next.status = "budget_limited"; next.budgetLimitedAt = now; } return next; } function buildUpdatedSessionGoalObjective(entry, objective, now) { if (!objective.trim()) throw new SessionGoalTransitionError("objective required"); const accounted = accountSessionGoalUsage(entry, now); if (!accounted) throw new SessionGoalTransitionError("goal not found"); if (accounted.status === "complete") throw new SessionGoalTransitionError(`goal is already ${accounted.status}`); return { ...accounted, objective, updatedAt: now }; } //#endregion export { buildUpdatedSessionGoalStatus as a, buildUpdatedSessionGoalObjective as i, accountSessionGoalUsage as n, buildCreatedSessionGoal as r, SessionGoalTransitionError as t };