121 lines
3.0 KiB
TypeScript
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];
|
|
}
|