Files
cozsweet-frontend-nextjs/src/stores/chat/helper/history.ts
T

121 lines
3.0 KiB
TypeScript

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<ChatState, "messages" | "historyLoaded"> {
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<string>();
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];
}