fix(chat): keep messages chronological across ID rollover

This commit is contained in:
Bohdan Triapitsyn
2026-08-14 16:53:05 +03:00
parent 7cf869d5eb
commit fe1f6130d6
23 changed files with 405 additions and 132 deletions
@@ -7,8 +7,8 @@ import {
startSessionLoadPerformanceEvent,
} from "./session-load-performance"
const createRecord = (sessionID: string, id = "msg_1") => ({
info: { id, sessionID, role: "user", time: { created: 1 } } as Message,
const createRecord = (sessionID: string, id = "msg_1", created = 1) => ({
info: { id, sessionID, role: "user", time: { created } } as Message,
parts: [{ id: `part_${id}`, messageID: id, sessionID, type: "text", text: "hello" }] as Part[],
})
@@ -65,8 +65,8 @@ describe("SessionMessageLoader", () => {
const { childStores, loader } = createLoader(async ({ sessionID, limit, before }) => {
calls.push({ limit, before })
return before
? response([createRecord(sessionID, "msg_older")])
: response([createRecord(sessionID, "msg_latest")], "older-cursor")
? response([createRecord(sessionID, "msg_older", 1)])
: response([createRecord(sessionID, "msg_latest", 2)], "older-cursor")
})
const target = { directory: "/repo", sessionID: "session-a" }
@@ -83,11 +83,35 @@ describe("SessionMessageLoader", () => {
{ limit: 100, before: "older-cursor" },
])
expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]?.map((message) => message.id))
.toEqual(["msg_latest", "msg_older"].sort())
.toEqual(["msg_older", "msg_latest"])
loader.dispose()
childStores.disposeAll()
})
test("keeps a post-rollover tail after legacy messages for shared runtime identities", async () => {
const runtimes = ["web", "desktop", "vscode", "mobile"]
for (const runtimeKey of runtimes) {
const childStores = new ChildStoreManager()
const sdk = {
session: {
messages: async ({ sessionID }: { sessionID: string }) => response([
createRecord(sessionID, "msg_000000000000Current", 200),
createRecord(sessionID, "msg_ffffffffffffLegacy", 100),
]),
},
} as unknown as OpencodeClient
const loader = new SessionMessageLoader(childStores, { sdk, runtimeKey })
const target = { directory: `/repo-${runtimeKey}`, sessionID: "session-a" }
await loader.ensure(target)
expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]?.map((message) => message.id))
.toEqual(["msg_ffffffffffffLegacy", "msg_000000000000Current"])
loader.dispose()
childStores.disposeAll()
}
})
test("loads every history page for an explicit complete-history request", async () => {
const calls: Array<{ before?: string }> = []
const { childStores, loader } = createLoader(async ({ sessionID, before }) => {