Spaces:
Runtime error
Runtime error
| import { NextResponse } from "next/server"; | |
| import { z } from "zod"; | |
| import { requireManagementAuth } from "@/lib/api/requireManagementAuth"; | |
| import { judgeFidelityBatch } from "@omniroute/open-sse/services/compression/eval/fidelityCheck"; | |
| import { createPricedJudgeClient } from "@/lib/compression/judgeModelClient"; | |
| import type { ProviderCredentials } from "@omniroute/open-sse/executors/base"; | |
| import { getProviderCredentials } from "@/sse/services/auth"; | |
| import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error"; | |
| export const dynamic = "force-dynamic"; | |
| const VerifyRequestSchema = z.object({ | |
| items: z | |
| .array(z.object({ id: z.string(), original: z.string(), compressed: z.string() })) | |
| .min(1) | |
| .max(20), | |
| provider: z.string().min(1), | |
| judgeModel: z.string().min(1), | |
| costCapUsd: z.number().positive().max(5).default(0.1), | |
| }); | |
| export async function POST(req: Request) { | |
| const authError = await requireManagementAuth(req); | |
| if (authError) return authError; | |
| let body: unknown; | |
| try { | |
| body = await req.json(); | |
| } catch { | |
| return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); | |
| } | |
| const parsed = VerifyRequestSchema.safeParse(body); | |
| if (!parsed.success) { | |
| return NextResponse.json( | |
| { error: "Invalid request", details: parsed.error.issues }, | |
| { status: 400 } | |
| ); | |
| } | |
| const { items, provider, judgeModel, costCapUsd } = parsed.data; | |
| try { | |
| const rawCredentials = await getProviderCredentials(provider); | |
| if (!rawCredentials) { | |
| return NextResponse.json( | |
| { error: `No credentials configured for provider "${provider}"` }, | |
| { status: 400 } | |
| ); | |
| } | |
| // Positively require a credential-shaped object before casting. This rejects the | |
| // current non-credential return shapes ({allRateLimited}, {allExpired}) AND any | |
| // future error shape, instead of denylisting known ones. The success return from | |
| // getProviderCredentials is a structural superset of ProviderCredentials; the extra | |
| // fields (id, provider, email, etc.) are ignored by the executor adapter. | |
| const looksLikeCredentials = | |
| typeof rawCredentials === "object" && | |
| rawCredentials !== null && | |
| "connectionId" in rawCredentials && | |
| ("apiKey" in rawCredentials || "accessToken" in rawCredentials); | |
| if (!looksLikeCredentials) { | |
| return NextResponse.json( | |
| { error: `Provider "${provider}" credentials are unavailable` }, | |
| { status: 503 } | |
| ); | |
| } | |
| const credentials = rawCredentials as unknown as ProviderCredentials; | |
| const client = createPricedJudgeClient(provider, credentials); | |
| const result = await judgeFidelityBatch(client, judgeModel, items, costCapUsd); | |
| return NextResponse.json(result); | |
| } catch (err: unknown) { | |
| const msg = err instanceof Error ? err.message : String(err); | |
| console.error("[/api/compression/compare/verify]", msg); | |
| return NextResponse.json( | |
| { error: "Verify failed", details: sanitizeErrorMessage(msg) }, | |
| { status: 500 } | |
| ); | |
| } | |
| } | |