History

[codex] fix: tolerate invalid latest user message timestamps (#3521)

Wout Stiens committed 3 months ago

Commit 43e2aea1 parent b655a9f2 files · +75 −1Browse files

Unified · Split

2 files
  1. packages/client-runtime/src/state/threadSort.test.ts +71 −0
  2. packages/client-runtime/src/state/threadSort.ts +4 −1
packages/client-runtime/src/state/threadSort.test.ts+71−0
@@ -0,0 +1,71 @@
1import { describe, expect, it } from "vite-plus/test";
2
3import { sortThreads, type ThreadSortInput } from "./threadSort.ts";
4
5type TestThread = { readonly id: string } & ThreadSortInput;
6
7function makeThread(overrides: Partial<TestThread> = {}): TestThread {
8 return {
9 id: "thread-1",
10 createdAt: "2026-03-09T10:00:00.000Z",
11 updatedAt: "2026-03-09T10:00:00.000Z",
12 messages: [],
13 latestUserMessageAt: null,
14 ...overrides,
15 };
16}
17
18describe("sortThreads", () => {
19 it("falls back to updatedAt and createdAt when latestUserMessageAt is invalid and there are no messages", () => {
20 const sorted = sortThreads(
21 [
22 makeThread({
23 id: "thread-1",
24 latestUserMessageAt: "not-a-date",
25 createdAt: "2026-03-09T10:00:00.000Z",
26 updatedAt: "2026-03-09T10:05:00.000Z",
27 }),
28 makeThread({
29 id: "thread-2",
30 latestUserMessageAt: "still-not-a-date",
31 createdAt: "invalid-created-at",
32 updatedAt: "invalid-updated-at",
33 }),
34 makeThread({
35 id: "thread-3",
36 latestUserMessageAt: "invalid-latest-user-message-at",
37 createdAt: "2026-03-09T10:06:00.000Z",
38 updatedAt: "invalid-updated-at",
39 }),
40 ],
41 "updated_at",
42 );
43
44 expect(sorted.map((thread) => thread.id)).toEqual(["thread-3", "thread-1", "thread-2"]);
45 });
46
47 it("falls back to the latest valid user message when latestUserMessageAt is invalid", () => {
48 const sorted = sortThreads(
49 [
50 makeThread({
51 id: "thread-1",
52 latestUserMessageAt: "invalid-latest-user-message-at",
53 updatedAt: "2026-03-09T10:00:00.000Z",
54 messages: [
55 { role: "user", createdAt: "2026-03-09T10:05:00.000Z" },
56 { role: "assistant", createdAt: "2026-03-09T10:30:00.000Z" },
57 { role: "user", createdAt: "2026-03-09T10:20:00.000Z" },
58 ],
59 }),
60 makeThread({
61 id: "thread-2",
62 createdAt: "2026-03-09T10:15:00.000Z",
63 updatedAt: "2026-03-09T10:15:00.000Z",
64 }),
65 ],
66 "updated_at",
67 );
68
69 expect(sorted.map((thread) => thread.id)).toEqual(["thread-1", "thread-2"]);
70 });
71});
packages/client-runtime/src/state/threadSort.ts+4−1
@@ -32,7 +32,10 @@ function getFirstSortableTimestamp(...values: Array<string | null | undefined>): · 31 unmodified lines
32 32
33function getLatestUserMessageTimestamp(thread: ThreadSortInput): number {33function getLatestUserMessageTimestamp(thread: ThreadSortInput): number {
34 if (thread.latestUserMessageAt) {34 if (thread.latestUserMessageAt) {
35 return toSortableTimestamp(thread.latestUserMessageAt) ?? Number.NEGATIVE_INFINITY;35 const latestUserMessageTimestamp = toSortableTimestamp(thread.latestUserMessageAt);
36 if (latestUserMessageTimestamp !== null) {
37 return latestUserMessageTimestamp;
38 }
36 }39 }
37 40
38 let latestUserMessageTimestamp: number | null = null;41 let latestUserMessageTimestamp: number | null = null;