fix(core): avoid empty transcript history pages (#7582)

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
This commit is contained in:
ytahdn 2026-07-23 16:37:35 +08:00 committed by GitHub
parent 3b3a593600
commit e58f995fae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 52 additions and 12 deletions

View file

@ -329,6 +329,32 @@ describe('SessionTranscriptReader', () => {
});
});
it('includes leading session metadata with the first backward page', async () => {
const sessionSource = {
...record('source', null, 'session source'),
type: 'system' as const,
subtype: 'session_source' as const,
};
await writeRecords([
sessionSource,
record('u1', 'source', 'first prompt'),
record('a1', 'u1', 'first answer'),
]);
const page = await new SessionTranscriptReader(workspaceDir).readPage(
sessionId,
{ direction: 'backward', limit: 100 },
);
expect(page.records.map((item) => item.uuid)).toEqual([
'source',
'u1',
'a1',
]);
expect(page.hasMore).toBe(false);
expect(page.nextCursorState).toBeUndefined();
});
it('keeps backward pages within a normal user turn boundary', async () => {
const toolCall = record('a-tool', 'u1', 'call tool');
const toolResult = {

View file

@ -517,24 +517,38 @@ function selectBackwardPageUuids(
break;
}
}
if (!alignedToReplayBoundary) {
let expandedSelection = false;
if (alignedToReplayBoundary && selectedStart > 0) {
let previousTurnStart = selectedStart - 1;
while (
previousTurnStart >= 0 &&
!isReplayTurnStart(index, index.activeUuids[previousTurnStart]!)
) {
previousTurnStart--;
}
if (previousTurnStart < 0) {
selectedStart = 0;
expandedSelection = true;
}
} else if (!alignedToReplayBoundary) {
while (
selectedStart > 0 &&
!isReplayTurnStart(index, index.activeUuids[selectedStart]!)
) {
selectedStart--;
}
if (maxBytes !== undefined) {
const alignedBytes = index.activeUuids
.slice(selectedStart, position)
.reduce((total, uuid) => total + recordSegmentBytes(index, uuid), 0);
if (alignedBytes > maxBytes) {
throw new SessionTranscriptPageTooLargeError(
sessionId,
alignedBytes,
maxBytes,
);
}
expandedSelection = true;
}
if (expandedSelection && maxBytes !== undefined) {
const alignedBytes = index.activeUuids
.slice(selectedStart, position)
.reduce((total, uuid) => total + recordSegmentBytes(index, uuid), 0);
if (alignedBytes > maxBytes) {
throw new SessionTranscriptPageTooLargeError(
sessionId,
alignedBytes,
maxBytes,
);
}
}