From a24d601b86ab188e672868c6aa8672b6a53246d6 Mon Sep 17 00:00:00 2001 From: Fusion Date: Fri, 15 May 2026 01:52:29 -0700 Subject: [PATCH] =?UTF-8?q?feat(FN-4583):=20complete=20Step=201=20?= =?UTF-8?q?=E2=80=94=20add=20chat=20room=20message=20tail=20ordering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fusion-Task-Id: FN-4583 Fusion-Task-Lineage: 4d9b088d-a705-4376-b547-15b37e5370aa --- .../src/__tests__/chat-store.rooms.test.ts | 19 +++++++++++++++++++ packages/core/src/chat-store.ts | 6 ++++-- packages/core/src/chat-types.ts | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/core/src/__tests__/chat-store.rooms.test.ts b/packages/core/src/__tests__/chat-store.rooms.test.ts index 672b6d707..8cb29e946 100644 --- a/packages/core/src/__tests__/chat-store.rooms.test.ts +++ b/packages/core/src/__tests__/chat-store.rooms.test.ts @@ -146,6 +146,25 @@ describe("ChatStore — rooms (FN-3805..FN-3811 contract)", () => { expect(store.listRoomMessagesSince(room.id, new Date().toISOString())).toEqual([]); }); + it("returns newest limited room window when order is desc while preserving ascending output", () => { + const room = store.createRoom({ name: "window-test" }); + + for (let i = 1; i <= 107; i += 1) { + store.addRoomMessage(room.id, { role: "user", content: `message-${i}` }); + } + + const newestWindow = store.getRoomMessages(room.id, { limit: 100, order: "desc" }); + expect(newestWindow).toHaveLength(100); + expect(newestWindow[0]?.content).toBe("message-8"); + expect(newestWindow.at(-1)?.content).toBe("message-107"); + expect(newestWindow.some((message) => message.content === "message-1")).toBe(false); + + const legacyWindow = store.getRoomMessages(room.id, { limit: 100 }); + expect(legacyWindow).toHaveLength(100); + expect(legacyWindow[0]?.content).toBe("message-1"); + expect(legacyWindow.at(-1)?.content).toBe("message-100"); + }); + it("keeps cross-room and direct-vs-room histories isolated", () => { const session = store.createSession({ agentId: "agent-1" }); store.addMessage(session.id, { role: "user", content: "direct" }); diff --git a/packages/core/src/chat-store.ts b/packages/core/src/chat-store.ts index d08e59448..450e5ddcf 100644 --- a/packages/core/src/chat-store.ts +++ b/packages/core/src/chat-store.ts @@ -926,14 +926,16 @@ export class ChatStore extends EventEmitter { params.push(filter.before); } + const order = filter?.order === "desc" ? "DESC" : "ASC"; const rows = this.db.prepare(` SELECT * FROM chat_room_messages WHERE ${whereClauses.join(" AND ")} - ORDER BY createdAt ASC + ORDER BY createdAt ${order} LIMIT ? OFFSET ? `).all(...params, filter?.limit ?? 100, filter?.offset ?? 0) as ChatRoomMessageRow[]; - return rows.map((row) => this.rowToRoomMessage(row)); + const normalizedRows = filter?.order === "desc" ? [...rows].reverse() : rows; + return normalizedRows.map((row) => this.rowToRoomMessage(row)); } listRoomMessagesSince( diff --git a/packages/core/src/chat-types.ts b/packages/core/src/chat-types.ts index fa7be410a..cdfc7ec78 100644 --- a/packages/core/src/chat-types.ts +++ b/packages/core/src/chat-types.ts @@ -263,4 +263,5 @@ export interface ChatRoomMessagesFilter { limit?: number; offset?: number; before?: string; + order?: "asc" | "desc"; }