Files
openclaw/src/gateway/session-transcript-anchor-reader.ts
Peter Steinberger 7d71d7cf6b fix(sessions): large histories no longer load entire transcripts (#108851)
* perf(sessions): bound SQLite history reads

* fix(sessions): keep history pagination gap-free

* test(sessions): use shared temp cleanup

* fix(sessions): reconcile mixed transcript projections

* fix(sessions): preserve strict schema migration

* refactor(sessions): trim internal export surface

* refactor(sessions): keep reader helpers private

* fix(sessions): reconcile transcript projections off requests

* test(sessions): await transcript projection repair

* fix(sessions): normalize projection worker failures

* fix(sessions): satisfy projection release gates
2026-07-16 14:11:33 -07:00

73 lines
2.3 KiB
TypeScript

import {
readSessionTranscriptMessageAnchorPage,
type SessionTranscriptReadScope,
} from "../config/sessions/session-accessor.js";
import {
isSqliteReadTarget,
resolveTranscriptReadTarget,
sqliteMessageEventWithSeq,
toTranscriptReadScope,
type ReadRecentSessionMessagesResult,
} from "./session-transcript-readers.js";
import { readSessionMessagesAroundIdWithStatsAsync as readSessionMessagesAroundIdWithStatsAsyncFile } from "./session-utils.fs-anchor.js";
type ReadSessionMessagesAroundIdResult = ReadRecentSessionMessagesResult & {
found: boolean;
hasOverreadContext: boolean;
offset: number;
};
/** Reads one message-id-anchored page from a single transcript snapshot. */
export async function readSessionMessagesAroundIdWithStatsAsync(
scope: SessionTranscriptReadScope,
opts: { messageId: string; maxMessages: number; allowResetArchiveFallback?: boolean },
): Promise<ReadSessionMessagesAroundIdResult> {
const target = resolveTranscriptReadTarget(scope);
const sessionFile =
!scope.sessionFile &&
scope.sessionEntry?.sessionId &&
scope.sessionEntry.sessionId !== scope.sessionId
? undefined
: target.sessionFile;
if (isSqliteReadTarget(target)) {
const page = readSessionTranscriptMessageAnchorPage(toTranscriptReadScope(target), opts);
if (!page.found) {
if (opts.allowResetArchiveFallback === true) {
return await readSessionMessagesAroundIdWithStatsAsyncFile(
target.sessionId,
target.storePath,
sessionFile,
opts,
target.agentId,
);
}
return {
found: false,
hasOverreadContext: false,
messages: [],
offset: 0,
totalMessages: page.totalMessages,
transcriptPath: target.sessionFile,
};
}
return {
found: true,
hasOverreadContext: page.hasOverreadContext,
messages: page.events.flatMap((entry) => {
const message = sqliteMessageEventWithSeq(entry);
return message === undefined ? [] : [message];
}),
offset: page.offset,
totalMessages: page.totalMessages,
transcriptPath: target.sessionFile,
};
}
return await readSessionMessagesAroundIdWithStatsAsyncFile(
target.sessionId,
target.storePath,
sessionFile,
opts,
target.agentId,
);
}