fix(ci): read Codex live sessions from sqlite

This commit is contained in:
Vincent Koc
2026-07-12 15:50:47 +08:00
parent e77cf7d44e
commit 8ac8754679
2 changed files with 92 additions and 17 deletions
@@ -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}`);
}
+56 -7
View File
@@ -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);