test: remove followup store path registry

This commit is contained in:
Peter Steinberger
2026-05-08 09:55:25 +01:00
parent d8b12faabc
commit 0c444d4da8

View File

@@ -20,9 +20,6 @@ let resolveQueuedReplyExecutionConfigActual:
| undefined;
let createFollowupRunner: typeof import("./followup-runner.js").createFollowupRunner;
let clearRuntimeConfigSnapshot: typeof import("../../config/config.js").clearRuntimeConfigSnapshot;
let loadSessionStore: typeof import("../../config/sessions/store.js").loadSessionStore;
let saveSessionStore: typeof import("../../config/sessions/store.js").saveSessionStore;
let clearSessionStoreCacheForTest: typeof import("../../config/sessions/store.js").clearSessionStoreCacheForTest;
let clearFollowupQueue: typeof import("./queue.js").clearFollowupQueue;
let enqueueFollowupRun: typeof import("./queue.js").enqueueFollowupRun;
let sessionRunAccounting: typeof import("./session-run-accounting.js");
@@ -37,7 +34,7 @@ const FOLLOWUP_TEST_QUEUES = new Map<
lastRun?: FollowupRun["run"];
}
>();
const FOLLOWUP_TEST_SESSION_STORES = new Map<string, Record<string, SessionEntry>>();
const FOLLOWUP_TEST_SESSION_STORES = new Set<Record<string, SessionEntry>>();
function debugFollowupTest(message: string): void {
if (!FOLLOWUP_DEBUG) {
@@ -105,10 +102,9 @@ function expectNoBlockReplyTextIncludes(
}
function registerFollowupTestSessionStore(
storePath: string,
sessionStore: Record<string, SessionEntry>,
): void {
FOLLOWUP_TEST_SESSION_STORES.set(storePath, sessionStore);
FOLLOWUP_TEST_SESSION_STORES.add(sessionStore);
}
async function incrementRunCompactionCountForFollowupTest(
@@ -261,12 +257,16 @@ function refreshQueuedFollowupSessionForFollowupTest(params: {
async function persistRunSessionUsageForFollowupTest(
params: Parameters<typeof import("./session-run-accounting.js").persistRunSessionUsage>[0],
): Promise<void> {
const { storePath, sessionKey } = params;
if (!storePath || !sessionKey) {
const { sessionKey } = params;
if (!sessionKey) {
return;
}
const store = Array.from(FOLLOWUP_TEST_SESSION_STORES).find((candidate) =>
Object.hasOwn(candidate, sessionKey),
);
if (!store) {
return;
}
const registeredStore = FOLLOWUP_TEST_SESSION_STORES.get(storePath);
const store = registeredStore ?? loadSessionStore(storePath);
const entry = store[sessionKey];
if (!entry) {
return;
@@ -294,10 +294,6 @@ async function persistRunSessionUsageForFollowupTest(
nextEntry.totalTokens = promptTokens > 0 ? promptTokens : undefined;
nextEntry.totalTokensFresh = promptTokens > 0;
store[sessionKey] = nextEntry;
if (registeredStore) {
return;
}
await saveSessionStore(storePath, store);
}
async function loadFreshFollowupRunnerModuleForTest() {
@@ -307,12 +303,6 @@ async function loadFreshFollowupRunnerModuleForTest() {
"../../agents/model-fallback.js",
async () => await import("../../test-utils/model-fallback.mock.js"),
);
vi.doMock("../../agents/session-write-lock.js", () => ({
acquireSessionWriteLock: vi.fn(async () => ({
release: async () => {},
})),
resolveSessionLockMaxHoldFromTimeout: vi.fn(() => 1),
}));
vi.doMock("../../agents/pi-embedded.js", () => ({
abortEmbeddedPiRun: vi.fn(async () => false),
compactEmbeddedPiSession: (params: unknown) => compactEmbeddedPiSessionMock(params),
@@ -400,8 +390,6 @@ async function loadFreshFollowupRunnerModuleForTest() {
({ createFollowupRunner } = await import("./followup-runner.js"));
({ clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } =
await import("../../config/config.js"));
({ clearSessionStoreCacheForTest, loadSessionStore, saveSessionStore } =
await import("../../config/sessions/store.js"));
({ clearFollowupQueue, enqueueFollowupRun } = await import("./queue.js"));
sessionRunAccounting = await import("./session-run-accounting.js");
({ createMockFollowupRun, createMockTypingController } = await import("./test-helpers.js"));
@@ -465,7 +453,7 @@ afterEach(() => {
FOLLOWUP_TEST_SESSION_STORES.clear();
vi.clearAllTimers();
vi.useRealTimers();
clearSessionStoreCacheForTest();
vi.unstubAllEnvs();
if (!FOLLOWUP_DEBUG) {
return;
}
@@ -704,10 +692,6 @@ describe("createFollowupRunner runtime config", () => {
describe("createFollowupRunner compaction", () => {
it("adds verbose auto-compaction notice and tracks count", async () => {
const storePath = path.join(
await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-")),
"sessions.json",
);
const sessionEntry: SessionEntry = {
sessionId: "session",
updatedAt: Date.now(),
@@ -716,7 +700,7 @@ describe("createFollowupRunner compaction", () => {
main: sessionEntry,
};
const onBlockReply = vi.fn(async () => {});
registerFollowupTestSessionStore(storePath, sessionStore);
registerFollowupTestSessionStore(sessionStore);
mockCompactionRun({
willRetry: true,
@@ -730,7 +714,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry,
sessionStore,
sessionKey: "main",
storePath,
defaultModel: "anthropic/claude-opus-4-6",
});
@@ -749,20 +732,17 @@ describe("createFollowupRunner compaction", () => {
});
it("tracks auto-compaction from embedded result metadata even when no compaction event is emitted", async () => {
const storePath = path.join(
await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-meta-")),
"sessions.json",
);
const sessionsDir = await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-meta-"));
const sessionEntry: SessionEntry = {
sessionId: "session",
sessionFile: path.join(path.dirname(storePath), "session.jsonl"),
sessionFile: path.join(sessionsDir, "session.jsonl"),
updatedAt: Date.now(),
};
const sessionStore: Record<string, SessionEntry> = {
main: sessionEntry,
};
const onBlockReply = vi.fn(async () => {});
registerFollowupTestSessionStore(storePath, sessionStore);
registerFollowupTestSessionStore(sessionStore);
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "final" }],
@@ -782,7 +762,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry,
sessionStore,
sessionKey: "main",
storePath,
defaultModel: "anthropic/claude-opus-4-6",
});
@@ -800,24 +779,21 @@ describe("createFollowupRunner compaction", () => {
expect(sessionStore.main.compactionCount).toBe(2);
expect(sessionStore.main.sessionId).toBe("session-rotated");
expect(await normalizeComparablePath(sessionStore.main.sessionFile ?? "")).toBe(
await normalizeComparablePath(path.join(path.dirname(storePath), "session-rotated.jsonl")),
await normalizeComparablePath(path.join(sessionsDir, "session-rotated.jsonl")),
);
});
it("refreshes queued followup runs to the rotated transcript", async () => {
const storePath = path.join(
await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-queue-")),
"sessions.json",
);
const sessionsDir = await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-queue-"));
const sessionEntry: SessionEntry = {
sessionId: "session",
sessionFile: path.join(path.dirname(storePath), "session.jsonl"),
sessionFile: path.join(sessionsDir, "session.jsonl"),
updatedAt: Date.now(),
};
const sessionStore: Record<string, SessionEntry> = {
main: sessionEntry,
};
registerFollowupTestSessionStore(storePath, sessionStore);
registerFollowupTestSessionStore(sessionStore);
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "final" }],
@@ -837,7 +813,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry,
sessionStore,
sessionKey: "main",
storePath,
defaultModel: "anthropic/claude-opus-4-6",
});
@@ -845,7 +820,7 @@ describe("createFollowupRunner compaction", () => {
prompt: "next",
run: {
sessionId: "session",
sessionFile: path.join(path.dirname(storePath), "session.jsonl"),
sessionFile: path.join(sessionsDir, "session.jsonl"),
},
});
const queueSettings: QueueSettings = { mode: "queue" };
@@ -855,7 +830,7 @@ describe("createFollowupRunner compaction", () => {
run: {
verboseLevel: "on",
sessionId: "session",
sessionFile: path.join(path.dirname(storePath), "session.jsonl"),
sessionFile: path.join(sessionsDir, "session.jsonl"),
},
});
@@ -863,15 +838,11 @@ describe("createFollowupRunner compaction", () => {
expect(queuedNext.run.sessionId).toBe("session-rotated");
expect(await normalizeComparablePath(queuedNext.run.sessionFile)).toBe(
await normalizeComparablePath(path.join(path.dirname(storePath), "session-rotated.jsonl")),
await normalizeComparablePath(path.join(sessionsDir, "session-rotated.jsonl")),
);
});
it("does not count failed compaction end events in followup runs", async () => {
const storePath = path.join(
await fs.mkdtemp(path.join(tmpdir(), "openclaw-compaction-failed-")),
"sessions.json",
);
const sessionEntry: SessionEntry = {
sessionId: "session",
updatedAt: Date.now(),
@@ -880,7 +851,7 @@ describe("createFollowupRunner compaction", () => {
main: sessionEntry,
};
const onBlockReply = vi.fn(async () => {});
registerFollowupTestSessionStore(storePath, sessionStore);
registerFollowupTestSessionStore(sessionStore);
const runner = createFollowupRunner({
opts: { onBlockReply },
@@ -889,7 +860,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry,
sessionStore,
sessionKey: "main",
storePath,
defaultModel: "anthropic/claude-opus-4-6",
});
@@ -925,7 +895,6 @@ describe("createFollowupRunner compaction", () => {
it("injects the post-compaction refresh prompt before followup runs after preflight compaction", async () => {
const workspaceDir = await fs.mkdtemp(path.join(tmpdir(), "openclaw-preflight-followup-"));
const storePath = path.join(workspaceDir, "sessions.json");
const transcriptPath = path.join(workspaceDir, "session.jsonl");
await fs.writeFile(
transcriptPath,
@@ -961,7 +930,7 @@ describe("createFollowupRunner compaction", () => {
const sessionStore: Record<string, SessionEntry> = {
main: sessionEntry,
};
registerFollowupTestSessionStore(storePath, sessionStore);
registerFollowupTestSessionStore(sessionStore);
compactEmbeddedPiSessionMock.mockResolvedValueOnce({
ok: true,
@@ -979,7 +948,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry?: SessionEntry;
sessionStore?: Record<string, SessionEntry>;
sessionKey?: string;
storePath?: string;
}) => {
await compactEmbeddedPiSessionMock({
sessionFile: transcriptPath,
@@ -1001,16 +969,6 @@ describe("createFollowupRunner compaction", () => {
if (params.sessionKey && params.sessionStore) {
params.sessionStore[params.sessionKey] = updatedEntry;
}
if (params.storePath && params.sessionKey) {
const registeredStore = FOLLOWUP_TEST_SESSION_STORES.get(params.storePath);
if (registeredStore) {
registeredStore[params.sessionKey] = updatedEntry;
} else {
const store = loadSessionStore(params.storePath);
store[params.sessionKey] = updatedEntry;
await saveSessionStore(params.storePath, store);
}
}
}
return updatedEntry;
},
@@ -1034,7 +992,6 @@ describe("createFollowupRunner compaction", () => {
sessionEntry,
sessionStore,
sessionKey: "main",
storePath,
defaultModel: "anthropic/claude-opus-4-6",
agentCfgContextTokens: 100_000,
});
@@ -1128,11 +1085,10 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry: SessionEntry;
sessionStore: Record<string, SessionEntry>;
sessionKey: string;
storePath: string;
}> = {},
) {
if (overrides.storePath && overrides.sessionStore) {
registerFollowupTestSessionStore(overrides.storePath, overrides.sessionStore);
if (overrides.sessionStore) {
registerFollowupTestSessionStore(overrides.sessionStore);
}
return createFollowupRunner({
opts: { onBlockReply },
@@ -1142,7 +1098,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry: overrides.sessionEntry,
sessionStore: overrides.sessionStore,
sessionKey: overrides.sessionKey,
storePath: overrides.storePath,
});
}
@@ -1153,7 +1108,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry: SessionEntry;
sessionStore: Record<string, SessionEntry>;
sessionKey: string;
storePath: string;
}>;
}) {
const onBlockReply = createAsyncReplySpy();
@@ -1175,7 +1129,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
}
it("persists usage even when replies are suppressed", async () => {
const storePath = "/tmp/openclaw-followup-usage.json";
const sessionKey = "main";
const sessionEntry: SessionEntry = { sessionId: "session", updatedAt: Date.now() };
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
@@ -1212,14 +1165,12 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry,
sessionStore,
sessionKey,
storePath,
},
queued: baseQueuedRun("slack"),
});
expect(onBlockReply).not.toHaveBeenCalled();
const persistCall = requireMockCallArg(persistSpy, 0);
expect(persistCall.storePath).toBe(storePath);
expect(persistCall.sessionKey).toBe(sessionKey);
expect(persistCall.modelUsed).toBe("claude-opus-4-6");
expect(persistCall.providerUsed).toBe("anthropic");
@@ -1232,7 +1183,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
});
it("passes queued config into usage persistence during drained followups", async () => {
const storePath = "/tmp/openclaw-followup-usage-cfg.json";
const sessionKey = "main";
const sessionEntry: SessionEntry = { sessionId: "session", updatedAt: Date.now() };
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
@@ -1262,7 +1212,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry,
sessionStore,
sessionKey,
storePath,
});
await expect(
@@ -1276,14 +1225,12 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
).resolves.toBeUndefined();
const persistCall = requireMockCallArg(persistSpy, 0);
expect(persistCall.storePath).toBe(storePath);
expect(persistCall.sessionKey).toBe(sessionKey);
expect(persistCall.cfg).toBe(cfg);
persistSpy.mockRestore();
});
it("uses providerUsed for snapshot freshness when agent metadata overrides the run provider", async () => {
const storePath = "/tmp/openclaw-followup-usage-provider.json";
const sessionKey = "main";
const sessionEntry: SessionEntry = { sessionId: "session", updatedAt: Date.now() };
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
@@ -1308,7 +1255,6 @@ describe("createFollowupRunner messaging delivery and dedupe", () => {
sessionEntry,
sessionStore,
sessionKey,
storePath,
});
await expect(