import { NextResponse } from "next/server"; import { runSiteMenteVoiceTurn } from "../../../../lib/ai/siteMenteAgent"; export const runtime = "nodejs"; // Vapi webhook payload types interface VapiMessage { type: string; role?: string; transcript?: string; toolCallList?: Array<{ id: string; function: { name: string; arguments: string; }; }>; } interface VapiCall { id: string; } interface VapiWebhookPayload { message: VapiMessage; call: VapiCall; } export async function POST(request: Request) { try { const body = (await request.json()) as VapiWebhookPayload; const message = body.message; // Handle tool calls from Vapi if (message.toolCallList && message.toolCallList.length > 0) { const toolCall = message.toolCallList[0]; const toolCallId = toolCall.id; // Get the arguments from the tool call let args = {}; try { args = JSON.parse(toolCall.function.arguments || '{}'); } catch (e) { // If arguments is a string, use it directly args = { query: toolCall.function.arguments }; } // Process the voice request const transcript = args.query || ''; const response = await runSiteMenteVoiceTurn({ transcript: transcript, }); // Return EXACT Vapi format with toolCallId return NextResponse.json({ results: [ { toolCallId: toolCallId, result: response.reply, }, ], }); } // Handle regular transcripts if (!message || message.type !== "transcript" || !message.transcript) { return NextResponse.json({ results: [] }); } const transcript = message.transcript; const response = await runSiteMenteVoiceTurn({ transcript: transcript, }); // Return in Vapi's expected format - but we need a toolCallId // For transcripts without tool calls, we generate one return NextResponse.json({ results: [ { toolCallId: `call_${Date.now()}`, result: response.reply, }, ], }); } catch (error) { console.error("[SiteMente][Vapi] Voice route failed", error); return NextResponse.json( { results: [ { toolCallId: `call_${Date.now()}`, result: "Lo siento, tuve un problema. ¿Puedes repetir?" } ] }, { status: 200 } ); } }