import { z } from "zod"; import { guarded, body, sse } from "@/lib/api"; import { getMessage, updateMessage, deactivateFrom } from "@/lib/chat/store"; import { runAssistant } from "@/lib/chat/engine"; import type { Part } from "@/lib/ai/types"; export const maxDuration = 900; /** Approve or deny tool calls left pending on an assistant message, then continue the turn. */ export const POST = guarded(async (req) => { const b = await body(req, z.object({ messageId: z.string(), approve: z.array(z.string()), deny: z.array(z.string()).optional() })); const m = await getMessage(b.messageId); if (!m || m.role !== "assistant" || !m.parent_id) return Response.json({ error: "Message introuvable" }, { status: 404 }); const parts = (m.parts as Part[]).map(p => p.type === "tool_call" && p.status === "pending_approval" && b.deny?.includes(p.id) ? { ...p, status: "denied" as const, error: "Refusé par le propriétaire" } : p); await updateMessage(m.id, { parts, status: "complete" }); // The continuation is a fresh assistant turn that sees the previous partial answer + tool decisions. await deactivateFrom(m.conversation_id, m.id, false); return sse(async (emit, signal) => { emit("conversation", { id: m.conversation_id, userMessageId: m.parent_id, continued: m.id }); await runAssistant({ conversationId: m.conversation_id, modelId: m.model_id ?? undefined, routingMode: "manual", parentMessageId: m.id, signal, emit, approvedToolCallIds: b.approve }); }, req.signal); });