import { NextRequest, NextResponse } from 'next/server'; import type { ProviderId } from '@/types'; import { PROVIDER_MAP } from '@/lib/providers'; interface ModelsRequestBody { provider: ProviderId; apiKey?: string; baseUrl?: string; } export async function POST(req: NextRequest) { let body: ModelsRequestBody; try { body = await req.json(); } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }); } const { provider, apiKey, baseUrl } = body; const def = PROVIDER_MAP[provider]; const base = baseUrl?.trim() || def.defaultBaseUrl; try { let models: string[] = []; if (provider === 'anthropic') { const key = apiKey?.trim() || process.env.ANTHROPIC_API_KEY; if (!key) { return NextResponse.json({ error: 'No API key — enter one above or set ANTHROPIC_API_KEY in .env.local' }, { status: 400 }); } const res = await fetch('https://api.anthropic.com/v1/models?limit=100', { headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01', }, }); if (!res.ok) { const text = await res.text().catch(() => ''); return NextResponse.json({ error: `Anthropic: ${res.status} ${text}` }, { status: res.status }); } const data = await res.json(); models = (data.data ?? []).map((m: { id: string }) => m.id); } else if (provider === 'openrouter') { const headers: Record = {}; if (apiKey?.trim()) headers['Authorization'] = `Bearer ${apiKey.trim()}`; const res = await fetch('https://openrouter.ai/api/v1/models', { headers }); if (!res.ok) { const text = await res.text().catch(() => ''); return NextResponse.json({ error: `OpenRouter: ${res.status} ${text}` }, { status: res.status }); } const data = await res.json(); // Sort by id for easier browsing models = (data.data ?? []) .map((m: { id: string }) => m.id) .sort((a: string, b: string) => a.localeCompare(b)); } else { // LM Studio and Ollama — OpenAI-compatible /v1/models const res = await fetch(`${base}/models`, { headers: { Authorization: 'Bearer none' }, signal: AbortSignal.timeout(5000), }); if (!res.ok) { const text = await res.text().catch(() => ''); return NextResponse.json({ error: `${def.label}: ${res.status} ${text || 'Connection refused'}` }, { status: res.status }); } const data = await res.json(); models = (data.data ?? []).map((m: { id: string }) => m.id); } return NextResponse.json({ models }); } catch (err) { const msg = err instanceof Error ? err.message : 'Unknown error'; const isTimeout = msg.includes('timeout') || msg.includes('abort'); return NextResponse.json( { error: isTimeout ? `Could not reach ${def.label} — is it running?` : msg }, { status: 500 } ); } }