import toast from 'react-hot-toast'; const ANSWERS_PREFIX = 'answers'; export const generateAnswersImageMarkdown = (index: number, url: string) => { return `![${ANSWERS_PREFIX}-${index}](${url})`; }; export const cleanInputMessage = (content: string) => { return content .replace(/!\[input-.*?\)/g, '') .replace(/]*>.*?<\/video>/g, ''); }; export const cleanAnswerMessage = (content: string) => { return content.replace(/!\[answers.*?\.png\)/g, ''); }; type PlansBody = | { type: 'plans'; status: 'started'; } | { type: 'plans'; status: 'completed'; payload: Array>; }; type ToolsBody = | { type: 'tools'; status: 'started'; } | { type: 'tools'; status: 'completed'; payload: Array>; }; type CodeBody = | { type: 'code'; status: 'started'; } | { type: 'code'; status: 'running'; payload: { code: string; test: string; }; } | { type: 'code'; status: 'completed' | 'failed'; payload: { code: string; test: string; result: string; }; }; // this will return if self_reflection flag is true type ReflectionBody = | { type: 'self_reflection'; status: 'started'; } | { type: 'self_reflection'; status: 'completed' | 'failed'; payload: { feedback: string; success: boolean }; }; export type CodeResult = { code: string; test: string; result: string; }; export type ChunkBody = | { type: 'plans' | 'tools' | 'code' | 'final_code' | 'final_error'; status: 'started' | 'completed' | 'failed' | 'running'; payload: | Array> // PlansBody | ToolsBody | CodeResult; // CodeBody } | PrismaJson.FinalChatResult; /** * 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: string | null | undefined, ): [ChunkBody[], CodeResult?] => { if (!content) return [[], undefined]; const streamLogs = content.split('\n').filter(log => !!log); const buffer = streamLogs.pop(); const parsedStreamLogs: ChunkBody[] = []; try { streamLogs.forEach(streamLog => parsedStreamLogs.push(JSON.parse(streamLog)), ); } catch { toast.error('Error parsing stream logs'); return [[], undefined]; } if (buffer) { try { const lastLog = JSON.parse(buffer); parsedStreamLogs.push(lastLog); } catch { console.log(buffer); } } // Merge consecutive logs of the same type to the latest status const groupedSections = parsedStreamLogs.reduce((acc, curr) => { if ( acc.length > 0 && acc[acc.length - 1].type === curr.type && curr.status !== 'started' ) { acc[acc.length - 1] = curr; } else { acc.push(curr); } return acc; }, [] as ChunkBody[]); return [ groupedSections.filter(section => section.type !== 'final_code'), groupedSections.find(section => section.type === 'final_code') ?.payload as CodeResult, ]; };