import { env } from "@/lib/env"; type ChatMessage = { role: "system" | "user" | "assistant"; content: string; }; type ChatCompletion = { choices?: Array<{ message?: { content?: string; }; }>; usage?: { total_tokens?: number; }; }; export type LlmResult = { content: string; model: string; tokenCount?: number; raw?: unknown; }; export async function runLlmChat(messages: ChatMessage[], model = env.DEFAULT_LLM_MODEL): Promise { if (!env.LITELLM_BASE_URL || !env.LITELLM_API_KEY) { return { content: localFallback(messages), model: `${model}:fallback`, }; } const response = await fetch(`${env.LITELLM_BASE_URL.replace(/\/$/, "")}/chat/completions`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${env.LITELLM_API_KEY}`, }, body: JSON.stringify({ model, messages, temperature: 0.2, }), }); if (!response.ok) { const errorBody = await response.text(); throw new Error(`LiteLLM request failed: ${response.status} ${errorBody}`); } const data = (await response.json()) as ChatCompletion; return { content: data.choices?.[0]?.message?.content?.trim() ?? "", model, tokenCount: data.usage?.total_tokens, raw: data, }; } function localFallback(messages: ChatMessage[]) { const latestUserMessage = [...messages].reverse().find((message) => message.role === "user")?.content ?? ""; return [ "Lokaler Fallback: Es ist kein LiteLLM-Endpunkt konfiguriert.", "Die Anfrage wurde strukturiert angenommen und muss nach Konfiguration eines Modells erneut ausgeführt werden.", `Auszug der Anfrage: ${latestUserMessage.slice(0, 420)}`, ].join("\n\n"); }