Files
moltbot/src/commands/agent/session-store.ts
Jarvis fcb6859784 fix(memoryFlush): correct context token accounting for flush gating (#5343)
Merged via squash.

Prepared head SHA: afaa7bae3b
Co-authored-by: jarvis-medmatic <252428873+jarvis-medmatic@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-02-28 16:54:57 -08:00

109 lines
3.3 KiB
TypeScript

import { setCliSessionId } from "../../agents/cli-session.js";
import { resolveContextTokensForModel } from "../../agents/context.js";
import { DEFAULT_CONTEXT_TOKENS } from "../../agents/defaults.js";
import { isCliProvider } from "../../agents/model-selection.js";
import { deriveSessionTotalTokens, hasNonzeroUsage } from "../../agents/usage.js";
import type { OpenClawConfig } from "../../config/config.js";
import {
mergeSessionEntry,
setSessionRuntimeModel,
type SessionEntry,
updateSessionStore,
} from "../../config/sessions.js";
type RunResult = Awaited<
ReturnType<(typeof import("../../agents/pi-embedded.js"))["runEmbeddedPiAgent"]>
>;
export async function updateSessionStoreAfterAgentRun(params: {
cfg: OpenClawConfig;
contextTokensOverride?: number;
sessionId: string;
sessionKey: string;
storePath: string;
sessionStore: Record<string, SessionEntry>;
defaultProvider: string;
defaultModel: string;
fallbackProvider?: string;
fallbackModel?: string;
result: RunResult;
}) {
const {
cfg,
sessionId,
sessionKey,
storePath,
sessionStore,
defaultProvider,
defaultModel,
fallbackProvider,
fallbackModel,
result,
} = params;
const usage = result.meta.agentMeta?.usage;
const promptTokens = result.meta.agentMeta?.promptTokens;
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 contextTokens =
resolveContextTokensForModel({
cfg,
provider: providerUsed,
model: modelUsed,
contextTokensOverride: params.contextTokensOverride,
fallbackContextTokens: DEFAULT_CONTEXT_TOKENS,
}) ?? DEFAULT_CONTEXT_TOKENS;
const entry = sessionStore[sessionKey] ?? {
sessionId,
updatedAt: Date.now(),
};
const next: SessionEntry = {
...entry,
sessionId,
updatedAt: Date.now(),
contextTokens,
};
setSessionRuntimeModel(next, {
provider: providerUsed,
model: modelUsed,
});
if (isCliProvider(providerUsed, cfg)) {
const cliSessionId = result.meta.agentMeta?.sessionId?.trim();
if (cliSessionId) {
setCliSessionId(next, providerUsed, cliSessionId);
}
}
next.abortedLastRun = result.meta.aborted ?? false;
if (hasNonzeroUsage(usage)) {
const input = usage.input ?? 0;
const output = usage.output ?? 0;
const totalTokens = deriveSessionTotalTokens({
usage,
contextTokens,
promptTokens,
});
next.inputTokens = input;
next.outputTokens = output;
if (typeof totalTokens === "number" && Number.isFinite(totalTokens) && totalTokens > 0) {
next.totalTokens = totalTokens;
next.totalTokensFresh = true;
} else {
next.totalTokens = undefined;
next.totalTokensFresh = false;
}
next.cacheRead = usage.cacheRead ?? 0;
next.cacheWrite = usage.cacheWrite ?? 0;
}
if (compactionsThisRun > 0) {
next.compactionCount = (entry.compactionCount ?? 0) + compactionsThisRun;
}
const persisted = await updateSessionStore(storePath, (store) => {
const merged = mergeSessionEntry(store[sessionKey], next);
store[sessionKey] = merged;
return merged;
});
sessionStore[sessionKey] = persisted;
}