import { z } from "zod"; import { CommercialActionSchema } from "@/data/schemas/chat"; export const UiMessageSchema = z.object({ displayId: z.string().min(1), remoteId: z.string().min(1).optional(), clientId: z.string().min(1).optional(), content: z.string(), isFromAI: z.boolean(), date: z.string(), isSynthetic: z.boolean().optional(), imageUrl: z.string().optional(), imagePaywalled: z.boolean().optional(), audioUrl: z.string().optional(), locked: z.boolean().nullable().optional(), lockReason: z.string().nullable().optional(), isPrivate: z.boolean().nullable().optional(), lockedPrivate: z.boolean().nullable().optional(), privateMessageHint: z.string().nullable().optional(), commercialAction: CommercialActionSchema.nullable().optional(), }); export type UiMessage = z.infer; let fallbackClientId = 0; export function createRemoteUiMessageIdentity( remoteId: string, isFromAI: boolean, occurrence = 0, ): Pick { const role = isFromAI ? "assistant" : "user"; const base = `server:${encodeURIComponent(remoteId)}:${role}`; return { displayId: occurrence > 0 ? `${base}:${occurrence}` : base, remoteId, }; } export function createLegacyUiMessageIdentity( fingerprint: string, occurrence = 0, ): Pick { const base = `legacy:${hashIdentity(fingerprint)}`; return { displayId: occurrence > 0 ? `${base}:${occurrence}` : base, }; } export function createClientUiMessageIdentity( kind: "message" | "image" | "reply" | "error", ): Pick { const clientId = createClientId(); return { clientId, displayId: `client:${kind}:${clientId}`, }; } export const UiMessage = { create(input: Omit & { date?: string }): UiMessage { return UiMessageSchema.parse({ ...input, date: input.date ?? new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", }), }); }, }; function createClientId(): string { if (typeof globalThis.crypto?.randomUUID === "function") { return globalThis.crypto.randomUUID(); } fallbackClientId += 1; return `${Date.now().toString(36)}-${fallbackClientId.toString(36)}`; } function hashIdentity(value: string): string { let hash = 0x811c9dc5; for (let index = 0; index < value.length; index += 1) { hash ^= value.charCodeAt(index); hash = Math.imul(hash, 0x01000193); } return (hash >>> 0).toString(36); }