Fix older timeline loading after catch-up

This commit is contained in:
Mohamed Boudra
2026-06-03 22:32:12 +07:00
parent b510244518
commit 6d29092fe6
4 changed files with 200 additions and 1 deletions
@@ -386,7 +386,37 @@ export function selectProjectedTimelinePage(input: {
const limit = input.limit === undefined ? 0 : Math.max(0, Math.floor(input.limit));
const bounds = input.bounds ?? getTimelineBounds(input.rows);
const projectedAll = projectTimelineRows({ rows: input.rows, mode: "projected" });
if (projectedAll.length === 0 || !bounds) {
if (!bounds) {
return {
entries: [],
startSeq: null,
endSeq: null,
hasOlder: false,
hasNewer: false,
};
}
if (projectedAll.length === 0) {
if (input.direction === "after") {
const cursorSeq = input.cursorSeq ?? bounds.minSeq - 1;
return {
entries: [],
startSeq: null,
endSeq: null,
hasOlder: cursorSeq >= bounds.minSeq,
hasNewer: cursorSeq < bounds.maxSeq,
};
}
if (input.direction === "before") {
const cursorSeq = input.cursorSeq ?? bounds.maxSeq + 1;
return {
entries: [],
startSeq: null,
endSeq: null,
hasOlder: cursorSeq > bounds.minSeq,
hasNewer: cursorSeq <= bounds.maxSeq,
};
}
return {
entries: [],
startSeq: null,
@@ -362,6 +362,45 @@ describe("daemon E2E - timeline window", () => {
}
});
test("projected empty after fetch preserves older history availability", async () => {
const cwd = tmpCwd();
try {
const agent = await ctx.client.createAgent({
provider: "codex",
cwd,
title: "Timeline Empty After HasOlder Test",
modeId: "full-access",
});
for (let seq = 1; seq <= 160; seq += 1) {
await ctx.daemon.daemon.agentManager.appendTimelineItem(agent.id, {
type: "user_message",
text: `row ${seq}`,
});
}
const tail = await ctx.client.fetchAgentTimeline(agent.id, {
direction: "tail",
limit: 100,
projection: "projected",
});
expect(tail.hasOlder).toBe(true);
expect(tail.startCursor?.seq).toBe(61);
expect(tail.endCursor?.seq).toBe(160);
const after = await ctx.client.fetchAgentTimeline(agent.id, {
direction: "after",
cursor: { epoch: tail.epoch, seq: tail.endCursor?.seq ?? 160 },
limit: 100,
projection: "projected",
});
expect(after.entries).toHaveLength(0);
expect(after.hasOlder).toBe(true);
} finally {
rmSync(cwd, { recursive: true, force: true });
}
});
test("before fetch does not re-fetch full plain chat history", async () => {
const cwd = tmpCwd();
try {