diff --git a/scripts/e2e/lib/codex-npm-plugin-live/assertions.mjs b/scripts/e2e/lib/codex-npm-plugin-live/assertions.mjs index 41d4ce7d363f..29c1faa269af 100644 --- a/scripts/e2e/lib/codex-npm-plugin-live/assertions.mjs +++ b/scripts/e2e/lib/codex-npm-plugin-live/assertions.mjs @@ -120,6 +120,41 @@ function readCodexBinding(sessionId, sessionKey) { } } +function readSessionEntry(sessionId) { + const dbPath = path.join(stateDir(), "agents", "main", "agent", "openclaw-agent.sqlite"); + if (!fs.existsSync(dbPath)) { + throw new Error(`missing agent session database: ${dbPath}`); + } + const db = new DatabaseSync(dbPath, { readOnly: true }); + try { + const row = db + .prepare( + `SELECT se.session_key, se.entry_json, s.agent_harness_id + FROM sessions AS s + INNER JOIN session_entries AS se ON se.session_id = s.session_id + WHERE s.session_id = ? + ORDER BY se.updated_at DESC, se.session_key + LIMIT 1`, + ) + .get(sessionId); + if (!row || typeof row.session_key !== "string" || typeof row.entry_json !== "string") { + throw new Error(`missing session store entry for ${sessionId}`); + } + const entry = JSON.parse(row.entry_json); + return { + entry: { + ...entry, + agentHarnessId: + typeof row.agent_harness_id === "string" ? row.agent_harness_id : entry.agentHarnessId, + sessionId, + }, + sessionKey: row.session_key, + }; + } finally { + db.close(); + } +} + function configure() { const modelRef = process.argv[3] || "codex/gpt-5.4"; const state = stateDir(); @@ -442,16 +477,7 @@ function assertAgentTurn() { ); } - const sessionsDir = path.join(stateDir(), "agents", "main", "sessions"); - const storePath = path.join(sessionsDir, "sessions.json"); - const store = readJson(storePath); - const sessionMatch = Object.entries(store).find( - ([, candidate]) => candidate?.sessionId === sessionId, - ); - if (!sessionMatch) { - throw new Error(`missing session store entry for ${sessionId}: ${JSON.stringify(store)}`); - } - const [sessionKey, entry] = sessionMatch; + const { entry, sessionKey } = readSessionEntry(sessionId); if (entry.agentHarnessId !== "codex") { throw new Error(`expected codex harness in session entry, got ${entry.agentHarnessId}`); } diff --git a/test/scripts/codex-install-assertions.test.ts b/test/scripts/codex-install-assertions.test.ts index d17d5d9fb476..d756747ac763 100644 --- a/test/scripts/codex-install-assertions.test.ts +++ b/test/scripts/codex-install-assertions.test.ts @@ -171,6 +171,55 @@ function writeCodexBindingStateSqlite(params: { } } +function writeSessionStoreSqlite(params: { + stateDir: string; + sessionFile: string; + sessionId: string; + sessionKey: string; +}) { + const dbPath = path.join(params.stateDir, "agents", "main", "agent", "openclaw-agent.sqlite"); + mkdirSync(path.dirname(dbPath), { recursive: true }); + const db = new DatabaseSync(dbPath); + try { + db.exec(` + CREATE TABLE sessions ( + session_id TEXT NOT NULL PRIMARY KEY, + session_key TEXT NOT NULL, + agent_harness_id TEXT, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL + ); + CREATE TABLE session_entries ( + session_key TEXT NOT NULL PRIMARY KEY, + session_id TEXT NOT NULL, + entry_json TEXT NOT NULL, + updated_at INTEGER NOT NULL + ); + `); + const now = Date.now(); + db.prepare( + `INSERT INTO sessions ( + session_id, session_key, agent_harness_id, created_at, updated_at + ) VALUES (?, ?, ?, ?, ?)`, + ).run(params.sessionId, params.sessionKey, "codex", now, now); + db.prepare( + `INSERT INTO session_entries (session_key, session_id, entry_json, updated_at) + VALUES (?, ?, ?, ?)`, + ).run( + params.sessionKey, + params.sessionId, + JSON.stringify({ + sessionId: params.sessionId, + sessionFile: params.sessionFile, + agentHarnessId: "codex", + }), + now, + ); + } finally { + db.close(); + } +} + function createCodexNpmPluginLiveFixture(root: string, storedSessionId?: string) { const stateDir = path.join(root, "state"); const sessionsDir = path.join(stateDir, "agents", "main", "sessions"); @@ -184,13 +233,13 @@ function createCodexNpmPluginLiveFixture(root: string, storedSessionId?: string) payloads: [{ text: marker }], meta: { executionTrace: { winnerProvider: "codex" } }, }); - writeJson(path.join(sessionsDir, "sessions.json"), { - [sessionKey]: { - sessionId, - sessionFile, - agentHarnessId: "codex", - }, + writeSessionStoreSqlite({ + stateDir, + sessionFile, + sessionId, + sessionKey, }); + mkdirSync(sessionsDir, { recursive: true }); writeFileSync(sessionFile, '{"type":"session"}\n', "utf8"); writeJson(path.join(stateDir, "agents", "main", "codex-home", "sessions", "native.jsonl"), { threadId, @@ -286,7 +335,7 @@ describe("Codex install helpers", () => { expect(result.stderr).toBe(""); }); - it("accepts the SQLite-backed Codex binding in the npm live assertion", () => { + it("accepts SQLite-backed session and Codex binding state in the npm live assertion", () => { const root = makeTempDir(tempDirs, "openclaw-codex-npm-live-"); const fixture = createCodexNpmPluginLiveFixture(root);