clawdbot-037: add sqlite exact session lookup

This commit is contained in:
Josh Lehman
2026-06-01 08:23:47 -07:00
parent 467ed1c502
commit 61aa3d17fb
2 changed files with 53 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ import {
appendTranscriptEvent,
appendTranscriptMessage,
listSessionEntries,
loadExactSessionEntry,
loadSessionEntry,
loadTranscriptEvents,
patchSessionEntry,
@@ -17,6 +18,7 @@ import {
replaceSessionEntry,
updateSessionEntry,
upsertSessionEntry,
type ExactSessionEntry,
type SessionAccessScope,
type SessionEntrySummary,
type SessionTranscriptAccessScope,
@@ -31,6 +33,7 @@ import {
appendSqliteTranscriptEvent,
appendSqliteTranscriptMessage,
listSqliteSessionEntries,
loadExactSqliteSessionEntry,
loadSqliteSessionEntry,
loadSqliteTranscriptEvents,
loadSqliteTranscriptEventsSync,
@@ -48,6 +51,7 @@ type AccessorAdapter = {
entryScope(paths: TestPaths): SessionAccessScope;
transcriptReadScope(paths: TestPaths, id?: string): SessionTranscriptReadScope;
transcriptScope(paths: TestPaths, id?: string): SessionTranscriptAccessScope;
loadExactSessionEntry(scope: SessionAccessScope): ExactSessionEntry | undefined;
loadSessionEntry(scope: SessionAccessScope): SessionEntry | undefined;
listSessionEntries(scope: Partial<Omit<SessionAccessScope, "sessionKey">>): SessionEntrySummary[];
readSessionUpdatedAt(scope: SessionAccessScope): number | undefined;
@@ -106,6 +110,7 @@ const fileBackedAdapter: AccessorAdapter = {
storePath: paths.storePath,
}),
loadSessionEntry,
loadExactSessionEntry,
listSessionEntries,
readSessionUpdatedAt,
upsertSessionEntry,
@@ -140,6 +145,7 @@ const sqliteAdapter: AccessorAdapter = {
storePath: paths.sqlitePath,
}),
loadSessionEntry: loadSqliteSessionEntry,
loadExactSessionEntry: loadExactSqliteSessionEntry,
listSessionEntries: listSqliteSessionEntries,
readSessionUpdatedAt: readSqliteSessionUpdatedAt,
upsertSessionEntry: upsertSqliteSessionEntry,
@@ -255,6 +261,30 @@ describe.each([fileBackedAdapter, sqliteAdapter])(
});
});
it("conforms for exact persisted-key lookup without canonical alias fallback", async () => {
const scope = adapter.entryScope(paths);
const mixedCaseScope = { ...scope, sessionKey: "AGENT:MAIN:MAIN" };
await adapter.upsertSessionEntry(scope, {
model: "gpt-5.5",
sessionId: "exact-session",
updatedAt: 10,
});
expect(adapter.loadSessionEntry(mixedCaseScope)).toMatchObject({
model: "gpt-5.5",
sessionId: "exact-session",
});
expect(adapter.loadExactSessionEntry(mixedCaseScope)).toBeUndefined();
expect(adapter.loadExactSessionEntry(scope)).toEqual({
sessionKey: "agent:main:main",
entry: expect.objectContaining({
model: "gpt-5.5",
sessionId: "exact-session",
}),
});
});
it("conforms for raw transcript event load and append", async () => {
const scope = adapter.transcriptScope(paths);
const readScope = adapter.transcriptReadScope(paths);

View File

@@ -22,6 +22,7 @@ import {
type OpenClawAgentDatabaseOptions,
} from "../../state/openclaw-agent-db.js";
import type {
ExactSessionEntry,
SessionAccessScope,
SessionEntryPatchContext,
SessionEntryPatchOptions,
@@ -82,6 +83,20 @@ export function loadSqliteSessionEntry(scope: SessionAccessScope): SessionEntry
return readSessionEntryRow(database, resolved.sessionKey)?.entry;
}
/** Loads one exact persisted-key entry from the additive SQLite session store. */
export function loadExactSqliteSessionEntry(
scope: SessionAccessScope,
): ExactSessionEntry | undefined {
const sessionKey = scope.sessionKey.trim();
if (!sessionKey) {
return undefined;
}
const resolved = resolveSqliteScope(scope);
const database = openOpenClawAgentDatabase(toDatabaseOptions(resolved));
const row = readExactSessionEntryRow(database, sessionKey);
return row ? { sessionKey, entry: row.entry } : undefined;
}
/** Lists session entries from the additive SQLite session store. */
export function listSqliteSessionEntries(
scope: Partial<Omit<SessionAccessScope, "sessionKey">> = {},
@@ -498,14 +513,18 @@ function parseSessionEntryRow(row: Pick<SessionEntryRow, "entry_json">): Session
function readSessionEntryRow(
database: OpenClawAgentDatabase,
sessionKey: string,
): { entry: SessionEntry; row: SessionEntryRow } | undefined {
return readExactSessionEntryRow(database, normalizeSqliteSessionKey(sessionKey));
}
function readExactSessionEntryRow(
database: OpenClawAgentDatabase,
sessionKey: string,
): { entry: SessionEntry; row: SessionEntryRow } | undefined {
const db = getSessionKysely(database.db);
const row = executeSqliteQueryTakeFirstSync(
database.db,
db
.selectFrom("session_entries")
.selectAll()
.where("session_key", "=", normalizeSqliteSessionKey(sessionKey)),
db.selectFrom("session_entries").selectAll().where("session_key", "=", sessionKey),
);
if (!row) {
return undefined;