import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock" import { createAnthropic } from "@ai-sdk/anthropic" import { createDeepSeek, deepseek } from "@ai-sdk/deepseek" import { createGateway } from "@ai-sdk/gateway" import { createGoogleGenerativeAI } from "@ai-sdk/google" import { createOpenAI } from "@ai-sdk/openai" import { createOpenRouter } from "@openrouter/ai-sdk-provider" import { generateText } from "ai" import { NextResponse } from "next/server" import { createOllama } from "ollama-ai-provider-v2" export const runtime = "nodejs" interface ValidateRequest { provider: string apiKey: string baseUrl?: string modelId: string // AWS Bedrock specific awsAccessKeyId?: string awsSecretAccessKey?: string awsRegion?: string } export async function POST(req: Request) { try { const body: ValidateRequest = await req.json() const { provider, apiKey, baseUrl, modelId, awsAccessKeyId, awsSecretAccessKey, awsRegion, } = body if (!provider || !modelId) { return NextResponse.json( { valid: false, error: "Provider and model ID are required" }, { status: 400 }, ) } // Validate credentials based on provider if (provider === "bedrock") { if (!awsAccessKeyId || !awsSecretAccessKey || !awsRegion) { return NextResponse.json( { valid: false, error: "AWS credentials (Access Key ID, Secret Access Key, Region) are required", }, { status: 400 }, ) } } else if (provider !== "ollama" && !apiKey) { return NextResponse.json( { valid: false, error: "API key is required" }, { status: 400 }, ) } let model: any switch (provider) { case "openai": { const openai = createOpenAI({ apiKey, ...(baseUrl && { baseURL: baseUrl }), }) model = openai.chat(modelId) break } case "anthropic": { const anthropic = createAnthropic({ apiKey, baseURL: baseUrl || "https://api.anthropic.com/v1", }) model = anthropic(modelId) break } case "google": { const google = createGoogleGenerativeAI({ apiKey, ...(baseUrl && { baseURL: baseUrl }), }) model = google(modelId) break } case "azure": { const azure = createOpenAI({ apiKey, baseURL: baseUrl, }) model = azure.chat(modelId) break } case "bedrock": { const bedrock = createAmazonBedrock({ accessKeyId: awsAccessKeyId, secretAccessKey: awsSecretAccessKey, region: awsRegion, }) model = bedrock(modelId) break } case "openrouter": { const openrouter = createOpenRouter({ apiKey, ...(baseUrl && { baseURL: baseUrl }), }) model = openrouter(modelId) break } case "deepseek": { if (baseUrl || apiKey) { const ds = createDeepSeek({ apiKey, ...(baseUrl && { baseURL: baseUrl }), }) model = ds(modelId) } else { model = deepseek(modelId) } break } case "siliconflow": { const sf = createOpenAI({ apiKey, baseURL: baseUrl || "https://api.siliconflow.com/v1", }) model = sf.chat(modelId) break } case "ollama": { const ollama = createOllama({ baseURL: baseUrl || "http://localhost:11434", }) model = ollama(modelId) break } case "gateway": { const gw = createGateway({ apiKey, ...(baseUrl && { baseURL: baseUrl }), }) model = gw(modelId) break } default: return NextResponse.json( { valid: false, error: `Unknown provider: ${provider}` }, { status: 400 }, ) } // Make a minimal test request const startTime = Date.now() await generateText({ model, prompt: "Say 'OK'", maxOutputTokens: 20, }) const responseTime = Date.now() - startTime return NextResponse.json({ valid: true, responseTime, }) } catch (error) { console.error("[validate-model] Error:", error) let errorMessage = "Validation failed" if (error instanceof Error) { // Extract meaningful error message if ( error.message.includes("401") || error.message.includes("Unauthorized") ) { errorMessage = "Invalid API key" } else if ( error.message.includes("404") || error.message.includes("not found") ) { errorMessage = "Model not found" } else if ( error.message.includes("429") || error.message.includes("rate limit") ) { errorMessage = "Rate limited - try again later" } else if (error.message.includes("ECONNREFUSED")) { errorMessage = "Cannot connect to server" } else { errorMessage = error.message.slice(0, 100) } } return NextResponse.json( { valid: false, error: errorMessage }, { status: 200 }, // Return 200 so client can read error message ) } }