mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 18:07:37 +02:00
93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
|
import { CURRENT_SESSION_VERSION, SessionManager } from "@mariozechner/pi-coding-agent";
|
|
import { estimateMessagesTokens } from "../../agents/compaction.js";
|
|
import { resolveSessionFilePath } from "../../config/sessions/paths.js";
|
|
import { resolveFreshSessionTotalTokens, type SessionEntry } from "../../config/sessions/types.js";
|
|
import { readSessionMessages } from "../../gateway/session-utils.fs.js";
|
|
|
|
function resolvePositiveTokenCount(value: number | undefined): number | undefined {
|
|
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
? Math.floor(value)
|
|
: undefined;
|
|
}
|
|
|
|
export function resolveParentForkTokenCountRuntime(params: {
|
|
parentEntry: SessionEntry;
|
|
storePath: string;
|
|
}): number | undefined {
|
|
const freshPersistedTokens = resolveFreshSessionTotalTokens(params.parentEntry);
|
|
if (typeof freshPersistedTokens === "number") {
|
|
return freshPersistedTokens;
|
|
}
|
|
|
|
try {
|
|
const transcriptMessages = readSessionMessages(
|
|
params.parentEntry.sessionId,
|
|
params.storePath,
|
|
params.parentEntry.sessionFile,
|
|
) as AgentMessage[];
|
|
if (transcriptMessages.length > 0) {
|
|
const estimatedTokens = estimateMessagesTokens(transcriptMessages);
|
|
const transcriptTokens = resolvePositiveTokenCount(
|
|
Number.isFinite(estimatedTokens) ? Math.ceil(estimatedTokens) : undefined,
|
|
);
|
|
if (typeof transcriptTokens === "number") {
|
|
return transcriptTokens;
|
|
}
|
|
}
|
|
} catch {
|
|
// Fall back to cached totals when the parent transcript cannot be read.
|
|
}
|
|
|
|
return resolvePositiveTokenCount(params.parentEntry.totalTokens);
|
|
}
|
|
|
|
export function forkSessionFromParentRuntime(params: {
|
|
parentEntry: SessionEntry;
|
|
agentId: string;
|
|
sessionsDir: string;
|
|
}): { sessionId: string; sessionFile: string } | null {
|
|
const parentSessionFile = resolveSessionFilePath(
|
|
params.parentEntry.sessionId,
|
|
params.parentEntry,
|
|
{ agentId: params.agentId, sessionsDir: params.sessionsDir },
|
|
);
|
|
if (!parentSessionFile || !fs.existsSync(parentSessionFile)) {
|
|
return null;
|
|
}
|
|
try {
|
|
const manager = SessionManager.open(parentSessionFile);
|
|
const leafId = manager.getLeafId();
|
|
if (leafId) {
|
|
const sessionFile = manager.createBranchedSession(leafId) ?? manager.getSessionFile();
|
|
const sessionId = manager.getSessionId();
|
|
if (sessionFile && sessionId) {
|
|
return { sessionId, sessionFile };
|
|
}
|
|
}
|
|
const sessionId = crypto.randomUUID();
|
|
const timestamp = new Date().toISOString();
|
|
const fileTimestamp = timestamp.replace(/[:.]/g, "-");
|
|
const sessionFile = path.join(manager.getSessionDir(), `${fileTimestamp}_${sessionId}.jsonl`);
|
|
const header = {
|
|
type: "session",
|
|
version: CURRENT_SESSION_VERSION,
|
|
id: sessionId,
|
|
timestamp,
|
|
cwd: manager.getCwd(),
|
|
parentSession: parentSessionFile,
|
|
};
|
|
fs.writeFileSync(sessionFile, `${JSON.stringify(header)}\n`, {
|
|
encoding: "utf-8",
|
|
mode: 0o600,
|
|
flag: "wx",
|
|
});
|
|
return { sessionId, sessionFile };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|