import toast from 'react-hot-toast'; const WIPLogTypes = ['plans', 'tools', 'code']; const AllLogTypes = [ 'plans', 'tools', 'code', 'final_code', 'final_error', ] as const; export type ChunkBody = { type: (typeof AllLogTypes)[number]; status: 'started' | 'completed' | 'failed' | 'running'; timestamp?: string; payload: | Array> // PlansBody | ToolsBody | PrismaJson.FinalCodeBody['payload'] // CodeBody & FinalCodeBody | PrismaJson.StructuredError; // ErrorBody }; export type WIPChunkBodyGroup = PrismaJson.MessageBody & { timestamp?: string; duration?: number; }; /** * Formats the stream logs and returns an array of grouped sections. * * @param content - The content of the stream logs. * @returns An array of grouped sections and an optional final code result. */ export const formatStreamLogs = ( content: WIPChunkBodyGroup[] | null, result: PrismaJson.FinalResultBody | null, ): { formattedSections: WIPChunkBodyGroup[]; finalResult?: PrismaJson.FinalCodeBody['payload']; finalError?: PrismaJson.StructuredError; } => { if (!content) return { formattedSections: [], }; // Merge consecutive logs of the same type to the latest status const groupedSections = [...content, ...(result ? [result] : [])].reduce( (acc: WIPChunkBodyGroup[], curr: WIPChunkBodyGroup) => { const lastGroup = acc[acc.length - 1]; if ( acc.length > 0 && lastGroup.type === curr.type && curr.status !== 'started' ) { acc[acc.length - 1] = { ...curr, // always use the timestamp of the first log timestamp: lastGroup?.timestamp, // duration is the difference between the last log and the first log duration: lastGroup?.timestamp && curr.timestamp ? Date.parse(curr.timestamp) - Date.parse(lastGroup.timestamp) : undefined, }; } else { acc.push(curr); } return acc; }, [], ); return { formattedSections: groupedSections.filter(section => WIPLogTypes.includes(section.type), ), finalResult: groupedSections.find(section => section.type === 'final_code') ?.payload as PrismaJson.FinalCodeBody['payload'], finalError: groupedSections.find(section => section.type === 'final_error') ?.payload as PrismaJson.StructuredError, }; };