import type { AiArtifactSchema, AiChartSchema, AiChatMessage, AiFormSchema, AiReviewSchema, } from './types'; export function mergeById( current: T[] | undefined, incoming: T | T[] | undefined, ): T[] { const items = Array.isArray(incoming) ? incoming : incoming ? [incoming] : []; if (!items.length) return current ?? []; const next = [...(current ?? [])]; for (const item of items) { if (!item || typeof item !== 'object') continue; const index = next.findIndex((existing) => existing.id === item.id); if (index === -1) { next.push(item); } else { next[index] = item; } } return next; } /** * 将统一 artifact 归入 uiArtifacts。 * * 注意:不再派发到 legacy 列表(forms/reviews/charts)——渲染层从 * uiArtifacts 派生,legacy 字段仅保留给历史消息(metadata 中只有 * a2uiForm/a2uiReview/a2uiChart 的老数据)作兼容读取。 */ export function mergeArtifactIntoMessage( message: AiChatMessage, artifact: AiArtifactSchema, ): AiChatMessage { message.uiArtifacts = mergeById(message.uiArtifacts, artifact); return message; } /** * 从 uiArtifacts 派生 legacy 列表(渲染用)。 * 仅当 message 上没有显式 legacy 数据(历史消息)时,渲染层回退到 message.forms 等。 */ export function deriveForms(message: AiChatMessage): AiFormSchema[] { return (message.uiArtifacts ?? []) .filter((artifact) => artifact.type === 'form') .map((artifact) => artifact.payload) .filter((payload): payload is AiFormSchema => Boolean(payload) && typeof payload === 'object'); } export function deriveReviews(message: AiChatMessage): AiReviewSchema[] { return (message.uiArtifacts ?? []) .filter((artifact) => artifact.type === 'review') .map((artifact) => artifact.payload) .filter( (payload): payload is AiReviewSchema => Boolean(payload) && typeof payload === 'object', ); } export function deriveCharts(message: AiChatMessage): AiChartSchema[] { return (message.uiArtifacts ?? []) .filter((artifact) => artifact.type === 'chart') .map((artifact) => artifact.payload) .filter((payload): payload is AiChartSchema => Boolean(payload) && typeof payload === 'object'); }