import { apiError } from "@/lib/api"; import { getBuilderRunEvents, getOrStartBuilderRun, } from "@/lib/builder-runs"; import { encodeSse, sseResponse } from "@/lib/sse"; import { builderRequestSchema } from "@/lib/validation"; export const runtime = "nodejs"; export const maxDuration = 120; const terminalStatuses = new Set(["complete", "stopped", "error"]); export async function POST(request: Request) { try { const input = builderRequestSchema.parse(await request.json()); const run = getOrStartBuilderRun(input); let cursor = input.afterSeq; const stream = new ReadableStream({ async start(controller) { try { while (!request.signal.aborted) { const snapshot = getBuilderRunEvents(run.id, cursor); if (!snapshot) { controller.enqueue( encodeSse({ type: "error", message: "节点任务已过期" }), ); controller.close(); return; } for (const event of snapshot.events) { controller.enqueue(encodeSse(event)); cursor = Math.max(cursor, event.seq ?? cursor); } if (terminalStatuses.has(snapshot.status)) { controller.close(); return; } await new Promise((resolve) => setTimeout(resolve, 100)); } } catch { try { controller.close(); } catch { // A disconnected editor can reconnect with the last event seq. } } }, }); return sseResponse(stream); } catch (error) { return apiError(error, "无法处理 Skill 对话"); } }