import type { UIMessageChunk } from "ai"; export type BackendSseEvent = { event: string; data: Record; }; export function backendEventToUiChunk( item: BackendSseEvent, textId: string, ): UIMessageChunk | null { if (item.event === "text_delta") { return { type: "text-delta", id: textId, delta: String(item.data.text || "") }; } if (item.event === "progress") { return { type: "data-cad-progress", id: `progress_${String(item.data.step || Date.now())}`, data: item.data, }; } if (["requirements_document", "completion_checklist", "completion_audit", "agent_thinking", "tool_call", "candidate_result", "candidate_review", "geometry_diagnostic", "geometry_conclusion", "step_review", "checkpoint", "rollback", "final_review", "task_terminal"].includes(item.event)) { const review = item.data.review && typeof item.data.review === "object" ? item.data.review as Record : null; const status = item.event === "task_terminal" ? (String(item.data.lifecycle || "") === "failed" ? "error" : "success") : (item.event === "candidate_review" && String(review?.verdict || "") === "reject") || (item.event === "final_review" && String(review?.verdict || "") === "repair" && Number(review?.confidence || 0) >= 0.85) ? "error" : String(item.data.status || "running"); return { type: "data-cad-progress", id: `${item.event}_${String(item.data.taskId || Date.now())}_${String(item.data.nodeId || "")}`, data: { step: item.event, label: ({ requirements_document: "冻结需求", completion_checklist: "完成清单", completion_audit: "完成审计", agent_thinking: "建模判断", tool_call: "建模工具", candidate_result: "候选构建", candidate_review: "候选独立复核", geometry_diagnostic: "几何诊断", geometry_conclusion: "几何结论", step_review: "步骤审查", checkpoint: "构建检查点", rollback: "回滚检查点", final_review: "最终视觉复核", task_terminal: "生成任务", } as Record)[item.event], status, message: String( item.data.message || item.data.reason || (review?.evidence instanceof Array ? review.evidence.join(";") : ""), ), ...(item.data.taskId ? { taskId: String(item.data.taskId) } : {}), ...(item.data.nodeId ? { nodeId: String(item.data.nodeId) } : {}), ...(item.data.lifecycle ? { lifecycle: String(item.data.lifecycle) } : {}), }, }; } if (item.event === "cad_result") { const taskId = String(item.data.taskId || ""); const revisionId = String(item.data.revisionId || Date.now()); return { type: "data-cad-result", // Each revision is a distinct progressive result. Reusing only the task // id makes the AI SDK reconcile intermediate revisions into one part. id: `result_${taskId}_${revisionId}`, data: item.data, }; } if (item.event === "cad_error") { return { type: "data-cad-error", id: `error_${Date.now()}`, data: item.data, }; } return null; }