import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; import { z } from "zod"; import { prisma } from "~/db.server"; import { requireAdminApiRequest } from "~/services/personalAccessToken.server"; export async function loader({ request, params }: LoaderFunctionArgs) { await requireAdminApiRequest(request); const model = await prisma.llmModel.findUnique({ where: { id: params.modelId }, include: { pricingTiers: { include: { prices: true }, orderBy: { priority: "asc" }, }, }, }); if (!model) { return json({ error: "Model not found" }, { status: 404 }); } return json({ model }); } const UpdateModelSchema = z.object({ modelName: z.string().min(1).optional(), matchPattern: z.string().min(1).optional(), startDate: z.string().nullable().optional(), provider: z.string().nullable().optional(), description: z.string().nullable().optional(), contextWindow: z.number().int().nullable().optional(), maxOutputTokens: z.number().int().nullable().optional(), capabilities: z.array(z.string()).optional(), isHidden: z.boolean().optional(), pricingUnit: z.string().nullable().optional(), pricingTiers: z .array( z.object({ name: z.string().min(1), isDefault: z.boolean().default(true), priority: z.number().int().default(0), conditions: z .array( z.object({ usageDetailPattern: z.string(), operator: z.enum(["gt", "gte", "lt", "lte", "eq", "neq"]), value: z.number(), }) ) .default([]), prices: z.record(z.string(), z.number()), }) ) .optional(), }); export async function action({ request, params }: ActionFunctionArgs) { await requireAdminApiRequest(request); const modelId = params.modelId!; if (request.method === "DELETE") { const existing = await prisma.llmModel.findUnique({ where: { id: modelId } }); if (!existing) { return json({ error: "Model not found" }, { status: 404 }); } await prisma.llmModel.delete({ where: { id: modelId } }); return json({ success: true }); } if (request.method !== "PUT") { return json({ error: "Method not allowed" }, { status: 405 }); } let body: unknown; try { body = await request.json(); } catch { return json({ error: "Invalid JSON body" }, { status: 400 }); } const parsed = UpdateModelSchema.safeParse(body); if (!parsed.success) { return json({ error: "Invalid request body", details: parsed.error.issues }, { status: 400 }); } const { modelName, matchPattern, startDate, pricingTiers, provider, description, contextWindow, maxOutputTokens, capabilities, isHidden, pricingUnit, } = parsed.data; // Validate regex if provided — strip (?i) POSIX flag since our registry handles it if (matchPattern) { try { const testPattern = matchPattern.startsWith("(?i)") ? matchPattern.slice(4) : matchPattern; new RegExp(testPattern); } catch { return json({ error: "Invalid regex in matchPattern" }, { status: 400 }); } } // Update model + tiers atomically const updated = await prisma.$transaction(async (tx) => { await tx.llmModel.update({ where: { id: modelId }, data: { ...(modelName !== undefined && { modelName }), ...(matchPattern !== undefined && { matchPattern }), ...(startDate !== undefined && { startDate: startDate ? new Date(startDate) : null }), ...(provider !== undefined && { provider }), ...(description !== undefined && { description }), ...(contextWindow !== undefined && { contextWindow }), ...(maxOutputTokens !== undefined && { maxOutputTokens }), ...(capabilities !== undefined && { capabilities }), ...(isHidden !== undefined && { isHidden }), ...(pricingUnit !== undefined && { pricingUnit }), }, }); if (pricingTiers) { await tx.llmPricingTier.deleteMany({ where: { modelId } }); for (const tier of pricingTiers) { await tx.llmPricingTier.create({ data: { modelId, name: tier.name, isDefault: tier.isDefault, priority: tier.priority, conditions: tier.conditions, prices: { create: Object.entries(tier.prices).map(([usageType, price]) => ({ modelId, usageType, price, })), }, }, }); } } return tx.llmModel.findUnique({ where: { id: modelId }, include: { pricingTiers: { include: { prices: true }, orderBy: { priority: "asc" } }, }, }); }); return json({ model: updated }); }