vision-agent / lib /utils /content.ts
wuyiqunLu
feat: update final_error to result and add cancel callback (#103)
7286745 unverified
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<Record<string, string>> // 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,
};
};