mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-22 06:08:13 +00:00
fix: preserve virtual session rotation locators
This commit is contained in:
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "../../config/sessions.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { upsertSessionEntry } from "../../config/sessions/store.js";
|
||||
import { replaceSqliteSessionTranscriptEvents } from "../../config/sessions/transcript-store.sqlite.js";
|
||||
@@ -128,4 +129,56 @@ describe("session-updates lifecycle hooks", () => {
|
||||
agentId: "main",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps SQLite transcript locators virtual when compaction rotates topic sessions", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-updates-sqlite-"));
|
||||
tempDirs.push(root);
|
||||
if (!previousStateDirCaptured) {
|
||||
previousStateDir = process.env.OPENCLAW_STATE_DIR;
|
||||
previousStateDirCaptured = true;
|
||||
}
|
||||
process.env.OPENCLAW_STATE_DIR = root;
|
||||
const sessionKey = "agent:main:forum:direct:compaction:topic:456";
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: "s1",
|
||||
topicId: 456,
|
||||
});
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "s1",
|
||||
transcriptPath: sessionFile,
|
||||
events: [{ type: "message" }],
|
||||
});
|
||||
const entry = {
|
||||
sessionId: "s1",
|
||||
sessionFile,
|
||||
updatedAt: Date.now(),
|
||||
compactionCount: 0,
|
||||
} as SessionEntry;
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[sessionKey]: entry,
|
||||
};
|
||||
upsertSessionEntry({ agentId: "main", sessionKey, entry });
|
||||
const cfg = { session: {} } as OpenClawConfig;
|
||||
|
||||
await incrementCompactionCount({
|
||||
cfg,
|
||||
sessionEntry: entry,
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
newSessionId: "s2",
|
||||
});
|
||||
|
||||
const expectedNextFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: "s2",
|
||||
topicId: 456,
|
||||
});
|
||||
expect(sessionStore[sessionKey]?.sessionFile).toBe(expectedNextFile);
|
||||
expect(sessionStore[sessionKey]?.sessionFile).toContain("sqlite-transcript://");
|
||||
expect(sessionStore[sessionKey]?.sessionFile).not.toMatch(/^sqlite-transcript:\/[^/]/u);
|
||||
const [endEvent] = hookRunnerMocks.runSessionEnd.mock.calls[0] ?? [];
|
||||
expect(endEvent?.sessionFile).toBe(sessionFile);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,10 +12,13 @@ import {
|
||||
import { ensureSkillsWatcher } from "../../agents/skills/refresh.js";
|
||||
import { hydrateResolvedSkills } from "../../agents/skills/snapshot-hydration.js";
|
||||
import {
|
||||
createSqliteSessionTranscriptLocator,
|
||||
resolveSessionFilePath,
|
||||
resolveSessionFilePathOptions,
|
||||
getSessionEntry,
|
||||
isSqliteSessionTranscriptLocator,
|
||||
mergeSessionEntry,
|
||||
parseSqliteSessionTranscriptLocator,
|
||||
type SessionEntry,
|
||||
upsertSessionEntry,
|
||||
} from "../../config/sessions.js";
|
||||
@@ -382,6 +385,14 @@ function rewriteSessionFileForNewSessionId(params: {
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
const sqliteScope = parseSqliteSessionTranscriptLocator(trimmed);
|
||||
if (sqliteScope) {
|
||||
return createSqliteSessionTranscriptLocator({
|
||||
agentId: sqliteScope.agentId,
|
||||
sessionId: params.nextSessionId,
|
||||
topicId: extractSqliteTranscriptTopicId(trimmed, params.previousSessionId),
|
||||
});
|
||||
}
|
||||
const base = path.basename(trimmed);
|
||||
if (!base.endsWith(".jsonl")) {
|
||||
return undefined;
|
||||
@@ -404,3 +415,23 @@ function rewriteSessionFileForNewSessionId(params: {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function extractSqliteTranscriptTopicId(
|
||||
locator: string,
|
||||
previousSessionId: string,
|
||||
): string | undefined {
|
||||
if (!isSqliteSessionTranscriptLocator(locator)) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const url = new URL(locator.trim());
|
||||
const fileName = decodeURIComponent(url.pathname.replace(/^\/+/u, ""));
|
||||
const topicPrefix = `${previousSessionId}-topic-`;
|
||||
if (!fileName.endsWith(".jsonl") || !fileName.startsWith(topicPrefix)) {
|
||||
return undefined;
|
||||
}
|
||||
return fileName.slice(topicPrefix.length, -".jsonl".length);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user