mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-22 06:08:13 +00:00
test: use sqlite locators in session lifecycle tests
This commit is contained in:
@@ -4,6 +4,7 @@ import path from "node:path";
|
||||
import { expect, test, vi } from "vitest";
|
||||
import { readTranscriptState } from "../agents/transcript/transcript-state.js";
|
||||
import { getSessionEntry, upsertSessionEntry } from "../config/sessions.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js";
|
||||
import { replaceSqliteSessionTranscriptEvents } from "../config/sessions/transcript-store.sqlite.js";
|
||||
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
@@ -23,6 +24,10 @@ import {
|
||||
|
||||
const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness();
|
||||
|
||||
function sqliteTranscript(sessionId: string, agentId = DEFAULT_AGENT_ID): string {
|
||||
return createSqliteSessionTranscriptLocator({ agentId, sessionId });
|
||||
}
|
||||
|
||||
test("sessions.compaction.* lists checkpoints and branches or restores from pre-compaction snapshots", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const fixture = await createCheckpointFixture(dir);
|
||||
@@ -212,10 +217,11 @@ test("sessions.compaction.* lists checkpoints and branches or restores from pre-
|
||||
|
||||
test("sessions.compact without maxLines runs embedded manual compaction for checkpoint-capable flows", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const sessionFile = sqliteTranscript("sess-main");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: DEFAULT_AGENT_ID,
|
||||
sessionId: "sess-main",
|
||||
transcriptPath: path.join(dir, "sess-main.jsonl"),
|
||||
transcriptPath: sessionFile,
|
||||
events: [
|
||||
{
|
||||
type: "session",
|
||||
@@ -236,7 +242,7 @@ test("sessions.compact without maxLines runs embedded manual compaction for chec
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:main",
|
||||
entry: sessionStoreEntry("sess-main", {
|
||||
sessionFile: path.join(dir, "sess-main.jsonl"),
|
||||
sessionFile,
|
||||
thinkingLevel: "medium",
|
||||
reasoningLevel: "stream",
|
||||
}),
|
||||
@@ -260,7 +266,7 @@ test("sessions.compact without maxLines runs embedded manual compaction for chec
|
||||
expect.objectContaining({
|
||||
sessionId: "sess-main",
|
||||
sessionKey: "agent:main:main",
|
||||
sessionFile: expect.stringMatching(/sess-main\.jsonl$/),
|
||||
sessionFile,
|
||||
config: expect.any(Object),
|
||||
provider: expect.any(String),
|
||||
model: expect.any(String),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import path from "node:path";
|
||||
import { expect, test } from "vitest";
|
||||
import { createSqliteSessionTranscriptLocator, getSessionEntry } from "../config/sessions.js";
|
||||
import { replaceSqliteSessionTranscriptEvents } from "../config/sessions/transcript-store.sqlite.js";
|
||||
@@ -20,6 +19,10 @@ import {
|
||||
|
||||
const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness();
|
||||
|
||||
function sqliteTranscript(sessionId: string): string {
|
||||
return createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
|
||||
}
|
||||
|
||||
test("sessions.delete rejects main and aborts active runs", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
await writeSingleLineSession(dir, "sess-main", "hello");
|
||||
@@ -45,7 +48,7 @@ test("sessions.delete rejects main and aborts active runs", async () => {
|
||||
expect(deleted.payload?.deleted).toBe(true);
|
||||
expectActiveRunCleanup(
|
||||
"agent:main:discord:group:dev",
|
||||
["discord:group:dev", "agent:main:discord:group:dev", "sess-active"],
|
||||
["agent:main:discord:group:dev", "sess-active"],
|
||||
"sess-active",
|
||||
);
|
||||
expect(bundleMcpRuntimeMocks.disposeSessionMcpRuntime).toHaveBeenCalledWith("sess-active");
|
||||
@@ -171,7 +174,7 @@ test("sessions.delete closes ACP runtime handles before removing ACP sessions",
|
||||
test("sessions.delete emits session_end with deleted reason and no replacement", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
await writeSingleLineSession(dir, "sess-main", "hello");
|
||||
const transcriptPath = path.join(dir, "sess-delete.jsonl");
|
||||
const transcriptPath = sqliteTranscript("sess-delete");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-delete",
|
||||
@@ -211,7 +214,7 @@ test("sessions.delete emits session_end with deleted reason and no replacement",
|
||||
reason: "deleted",
|
||||
});
|
||||
expect((event as { sessionFile?: string } | undefined)?.sessionFile).toBe(
|
||||
createSqliteSessionTranscriptLocator({ agentId: "main", sessionId: "sess-delete" }),
|
||||
sqliteTranscript("sess-delete"),
|
||||
);
|
||||
expect((event as { nextSessionId?: string } | undefined)?.nextSessionId).toBeUndefined();
|
||||
expect(context).toMatchObject({
|
||||
@@ -339,7 +342,7 @@ test("sessions.delete returns unavailable when active run does not stop", async
|
||||
expect(deleted.error?.message ?? "").toMatch(/still active/i);
|
||||
expectActiveRunCleanup(
|
||||
"agent:main:discord:group:dev",
|
||||
["discord:group:dev", "agent:main:discord:group:dev", "sess-active"],
|
||||
["agent:main:discord:group:dev", "sess-active"],
|
||||
"sess-active",
|
||||
);
|
||||
expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).not.toHaveBeenCalled();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { expect, test } from "vitest";
|
||||
import {
|
||||
createSqliteSessionTranscriptLocator,
|
||||
@@ -55,6 +53,10 @@ function expectMainHookContext(context: HookEventRecord, sessionId: string) {
|
||||
expect(context.sessionId).toBe(sessionId);
|
||||
}
|
||||
|
||||
function sqliteTranscript(sessionId: string): string {
|
||||
return createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
|
||||
}
|
||||
|
||||
test("sessions.reset emits internal command hook with reason", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
await writeSingleLineSession(dir, "sess-main", "hello");
|
||||
@@ -104,8 +106,8 @@ test("sessions.reset emits internal command hook with reason", async () => {
|
||||
});
|
||||
|
||||
test("sessions.reset emits before_reset hook with transcript context", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const transcriptPath = path.join(dir, "sess-main.jsonl");
|
||||
await createSessionStoreDir();
|
||||
const transcriptPath = sqliteTranscript("sess-main");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-main",
|
||||
@@ -147,8 +149,8 @@ test("sessions.reset emits before_reset hook with transcript context", async ()
|
||||
});
|
||||
|
||||
test("sessions.reset emits before_reset hook with scoped SQLite transcript context", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const transcriptPath = path.join(dir, "missing-sess-main.jsonl");
|
||||
await createSessionStoreDir();
|
||||
const transcriptPath = sqliteTranscript("sess-main-sqlite");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-main-sqlite",
|
||||
@@ -201,8 +203,8 @@ test("sessions.reset emits before_reset hook with scoped SQLite transcript conte
|
||||
});
|
||||
|
||||
test("sessions.reset emits enriched session_end and session_start hooks", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const transcriptPath = path.join(dir, "sess-main.jsonl");
|
||||
await createSessionStoreDir();
|
||||
const transcriptPath = sqliteTranscript("sess-main");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-main",
|
||||
@@ -281,7 +283,7 @@ test("sessions.reset returns unavailable when active run does not stop", async (
|
||||
expect(reset.ok).toBe(false);
|
||||
expect(reset.error?.code).toBe("UNAVAILABLE");
|
||||
expect(reset.error?.message ?? "").toMatch(/still active/i);
|
||||
expectActiveRunCleanup("agent:main:main", ["main", "agent:main:main", "sess-main"], "sess-main");
|
||||
expectActiveRunCleanup("agent:main:main", ["agent:main:main", "sess-main"], "sess-main");
|
||||
expect(beforeResetHookMocks.runBeforeReset).not.toHaveBeenCalled();
|
||||
expect(waitCallCountAtSnapshotClear).toEqual([1]);
|
||||
expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).not.toHaveBeenCalled();
|
||||
@@ -292,9 +294,9 @@ test("sessions.reset returns unavailable when active run does not stop", async (
|
||||
});
|
||||
|
||||
test("sessions.reset emits before_reset for the entry actually reset in the SQLite patch", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const oldTranscriptPath = path.join(dir, "sess-old.jsonl");
|
||||
const newTranscriptPath = path.join(dir, "sess-new.jsonl");
|
||||
await createSessionStoreDir();
|
||||
const oldTranscriptPath = sqliteTranscript("sess-old");
|
||||
const newTranscriptPath = sqliteTranscript("sess-new");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-old",
|
||||
@@ -390,8 +392,8 @@ test("sessions.create with emitCommandHooks=true fires command:new hook against
|
||||
});
|
||||
|
||||
test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks against parent (#76957)", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const transcriptPath = path.join(dir, "sess-parent-hooks.jsonl");
|
||||
await createSessionStoreDir();
|
||||
const transcriptPath = sqliteTranscript("sess-parent-hooks");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-parent-hooks",
|
||||
@@ -448,17 +450,20 @@ test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks aga
|
||||
});
|
||||
|
||||
test("sessions.create with emitCommandHooks=true resets parent in place when session.dmScope is 'main' (#77434)", async () => {
|
||||
const { dir } = await createSessionStoreDir();
|
||||
const transcriptPath = path.join(dir, "sess-parent-dms.jsonl");
|
||||
await fs.writeFile(
|
||||
await createSessionStoreDir();
|
||||
const transcriptPath = sqliteTranscript("sess-parent-dms");
|
||||
replaceSqliteSessionTranscriptEvents({
|
||||
agentId: "main",
|
||||
sessionId: "sess-parent-dms",
|
||||
transcriptPath,
|
||||
`${JSON.stringify({
|
||||
type: "message",
|
||||
id: "m1",
|
||||
message: { role: "user", content: "hello before /new" },
|
||||
})}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
events: [
|
||||
{
|
||||
type: "message",
|
||||
id: "m1",
|
||||
message: { role: "user", content: "hello before /new" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testState.sessionConfig = { dmScope: "main" };
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user