import type { UiMessage } from "@/stores/chat/ui-message"; import type { ChatState } from "../chat-state"; // The initial history request remains bounded even though pagination is disabled. export const CHAT_HISTORY_LIMIT = 50; export function applyHistoryLoadedOutput( output: { messages: UiMessage[]; }, ): Pick { return { messages: output.messages, historyLoaded: true, }; } export function applyNetworkHistoryLoadedOutput( context: ChatState, output: { messages: UiMessage[]; localDisplayIds: readonly string[]; localCount: number; total: number; limit: number; }, ): Pick< ChatState, | "messages" | "historyLoaded" | "historyTotal" | "historyLimit" | "nextHistoryOffset" | "isLoadingMoreHistory" > { const localDisplayIds = new Set(output.localDisplayIds); const networkDisplayIds = new Set( output.messages.map((message) => message.displayId), ); const optimisticTail = context.messages.filter( (message) => !localDisplayIds.has(message.displayId) && !networkDisplayIds.has(message.displayId), ); const historyLimit = normalizeHistoryLimit(output.limit); return { messages: [...output.messages, ...optimisticTail], historyLoaded: true, historyTotal: Math.max(0, output.total), historyLimit, nextHistoryOffset: historyLimit, isLoadingMoreHistory: false, }; } export function applyOlderHistoryLoadedOutput( context: ChatState, output: { messages: UiMessage[]; offset: number; total: number; limit: number; }, ): Pick< ChatState, | "messages" | "historyTotal" | "historyLimit" | "nextHistoryOffset" | "isLoadingMoreHistory" > { const historyLimit = normalizeHistoryLimit( output.limit, context.historyLimit, ); return { messages: prependUniqueHistoryMessages(context.messages, output.messages), historyTotal: Math.max(0, output.total), historyLimit, nextHistoryOffset: output.offset + historyLimit, isLoadingMoreHistory: false, }; } export function canLoadMoreHistory(context: ChatState): boolean { return ( context.historyLoaded && !context.isLoadingMoreHistory && context.nextHistoryOffset < context.historyTotal ); } export function normalizeHistoryLimit( limit: number, fallback = CHAT_HISTORY_LIMIT, ): number { return Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : fallback; } export function prependUniqueHistoryMessages( currentMessages: readonly UiMessage[], olderMessages: readonly UiMessage[], ): UiMessage[] { const existingIds = new Set( currentMessages.map((message) => message.displayId), ); const pageIds = new Set(); const uniqueOlderMessages = olderMessages.filter((message) => { if ( existingIds.has(message.displayId) || pageIds.has(message.displayId) ) { return false; } pageIds.add(message.displayId); return true; }); return [...uniqueOlderMessages, ...currentMessages]; }