/** * POST /.netlify/functions/chat-claude * Body: { messages: [{role:"user"|"assistant"|"system", content:"..."}], system?: string, max_tokens?: number } * Env: ANTHROPIC_API_KEY, ANTHROPIC_MODEL (optional, defaults to claude-3-5-sonnet-latest) */ export async function handler(event) { if (event.httpMethod === "OPTIONS") { return { statusCode: 204, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Allow-Methods": "POST, OPTIONS", }, }; } if (event.httpMethod !== "POST") { return { statusCode: 405, body: "Method Not Allowed" }; } const headers = { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }; const key = process.env.ANTHROPIC_API_KEY; if (!key) { return { statusCode: 200, headers, body: JSON.stringify({ ok: false, error: "Missing ANTHROPIC_API_KEY in Netlify environment.", }), }; } let payload = {}; try { payload = JSON.parse(event.body || "{}"); } catch {} const model = process.env.ANTHROPIC_MODEL || "claude-3-5-sonnet-latest"; const max_tokens = Math.min(1024, Math.max(128, payload.max_tokens || 512)); const system = payload.system || "You are Volt, a concise, helpful assistant."; const body = { model, max_tokens, system, messages: payload.messages || [], }; try { const resp = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "content-type": "application/json", "x-api-key": key, "anthropic-version": "2023-06-01", }, body: JSON.stringify(body), }); const data = await resp.json(); if (!resp.ok) { return { statusCode: 200, headers, body: JSON.stringify({ ok: false, error: data.error || data }), }; } const text = (data.content && data.content[0] && data.content[0].text) || JSON.stringify(data); return { statusCode: 200, headers, body: JSON.stringify({ ok: true, text, raw: data }), }; } catch (err) { return { statusCode: 200, headers, body: JSON.stringify({ ok: false, error: String(err) }), }; } }