Load a conversation's history on the client
The conversation pages rendered their messages on the server, so a page the back button restored from the back-forward cache showed an old thread. The server now renders everything else (rail, header, composer) and the history (active session, latest messages, active task) loads from api/admin/bots/conversation-history once the page is on screen, with a loading line under the header, and again on a pageshow restore. Messages sent or pushed while it loads are merged with it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { BotMessageWithAttachments, ConversationHistory } from "@/src/types";
|
||||
import mergeLoadedHistory from "./merge-loaded-history";
|
||||
|
||||
function message({ id, session_id = 1 }: { id: number; session_id?: number }) {
|
||||
return { id, session_id, author: "bot", text: `#${id}` } as BotMessageWithAttachments;
|
||||
}
|
||||
|
||||
function history({ ids, session_id = 1 }: { ids: number[]; session_id?: number }) {
|
||||
return {
|
||||
session: { id: session_id },
|
||||
messages: ids.map((id) => message({ id, session_id })),
|
||||
has_more: false,
|
||||
task: null,
|
||||
} as ConversationHistory;
|
||||
}
|
||||
|
||||
const ids = (messages: BotMessageWithAttachments[]) => messages.map((m) => m.id);
|
||||
|
||||
describe("mergeLoadedHistory", () => {
|
||||
test("an empty thread takes the history", () => {
|
||||
expect(ids(mergeLoadedHistory({ shown: [], history: history({ ids: [1, 2] }) }))).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
test("keeps what arrived after the history, once", () => {
|
||||
const shown = [message({ id: 2 }), message({ id: 3 })];
|
||||
|
||||
expect(ids(mergeLoadedHistory({ shown, history: history({ ids: [1, 2] }) }))).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
test("an older copy of the thread gives way", () => {
|
||||
const shown = [message({ id: 1 }), message({ id: 2 })];
|
||||
|
||||
expect(ids(mergeLoadedHistory({ shown, history: history({ ids: [2, 4, 5] }) }))).toEqual([2, 4, 5]);
|
||||
});
|
||||
|
||||
test("another session's messages give way", () => {
|
||||
const shown = [message({ id: 9, session_id: 1 })];
|
||||
|
||||
expect(
|
||||
ids(mergeLoadedHistory({ shown, history: history({ ids: [10], session_id: 2 }) })),
|
||||
).toEqual([10]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { BotMessageWithAttachments, ConversationHistory } from "@/src/types";
|
||||
|
||||
type Params = {
|
||||
/**
|
||||
* What the thread shows now.
|
||||
*/
|
||||
shown: BotMessageWithAttachments[];
|
||||
history: ConversationHistory;
|
||||
};
|
||||
|
||||
/**
|
||||
* The thread once a history lands: its messages, then any the thread
|
||||
* already has from the same session that came after them (sent or pushed
|
||||
* while the history was on its way). Everything else the thread showed
|
||||
* (an older copy of the thread, another session's) gives way to it.
|
||||
*/
|
||||
export default function mergeLoadedHistory({ shown, history }: Params) {
|
||||
const loaded = history.messages;
|
||||
const last_id = Number(loaded[loaded.length - 1]?.id) || 0;
|
||||
|
||||
const later = shown.filter(
|
||||
(message) =>
|
||||
message.session_id == history.session.id &&
|
||||
Number(message.id) > last_id &&
|
||||
!loaded.some((m) => m.id == message.id),
|
||||
);
|
||||
|
||||
return [...loaded, ...later];
|
||||
}
|
||||
Reference in New Issue
Block a user