import { getSessionHistory } from "@/api/sessions" import { normalizeUnixTimestamp } from "@/features/chat/state" import type { ChatAttachment, ChatMessage } from "@/store/chat" function toChatAttachments(media?: string[]): ChatAttachment[] | undefined { if (!media || media.length === 0) { return undefined } const attachments = media .filter((item) => item.startsWith("data:image/")) .map((url) => ({ type: "image" as const, url })) return attachments.length > 0 ? attachments : undefined } export async function loadSessionMessages( sessionId: string, ): Promise { const detail = await getSessionHistory(sessionId) const fallbackTime = detail.updated return detail.messages.map((message, index) => ({ id: `hist-${index}-${Date.now()}`, role: message.role, content: message.content, kind: message.role === "assistant" ? "normal" : undefined, attachments: toChatAttachments(message.media), timestamp: fallbackTime, })) } function normalizeMessageTimestamp(timestamp: number | string): string { if (typeof timestamp === "number") { return String(normalizeUnixTimestamp(timestamp)) } const trimmed = timestamp.trim() if (/^-?\d+(\.\d+)?$/.test(trimmed)) { return String(normalizeUnixTimestamp(Number(trimmed))) } const parsed = Date.parse(trimmed) return Number.isNaN(parsed) ? trimmed : String(parsed) } function messageSignature(message: ChatMessage): string { const attachmentSignature = (message.attachments ?? []) .map((attachment) => `${attachment.type}\u0001${attachment.url}`) .join("\u0002") return `${message.role}\u0000${message.content}\u0000${normalizeMessageTimestamp( message.timestamp, )}\u0000${message.kind ?? ""}\u0000${attachmentSignature}` } function comparableTimestamp(timestamp: number | string): number { const normalized = normalizeMessageTimestamp(timestamp) const numeric = Number(normalized) return Number.isFinite(numeric) ? numeric : 0 } export function mergeHistoryMessages( historyMessages: ChatMessage[], currentMessages: ChatMessage[], ): ChatMessage[] { const currentIds = new Set(currentMessages.map((message) => message.id)) const currentSignatures = new Set( currentMessages.map((message) => messageSignature(message)), ) const merged = [ ...historyMessages.filter( (message) => !currentIds.has(message.id) && !currentSignatures.has(messageSignature(message)), ), ...currentMessages, ] return merged.sort( (left, right) => comparableTimestamp(left.timestamp) - comparableTimestamp(right.timestamp), ) }