import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; import { Prisma } from "@agentlens/database"; import { auth } from "@/auth"; export async function GET(request: NextRequest) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { searchParams } = new URL(request.url); const page = parseInt(searchParams.get("page") ?? "1", 10); const limit = parseInt(searchParams.get("limit") ?? "20", 10); const type = searchParams.get("type"); const search = searchParams.get("search"); const sort = searchParams.get("sort") ?? "newest"; // Validate pagination if (isNaN(page) || page < 1) { return NextResponse.json( { error: "Invalid page parameter. Must be a positive integer." }, { status: 400 } ); } if (isNaN(limit) || limit < 1 || limit > 100) { return NextResponse.json( { error: "Invalid limit parameter. Must be between 1 and 100." }, { status: 400 } ); } // Validate type const validTypes = [ "TOOL_SELECTION", "ROUTING", "RETRY", "ESCALATION", "MEMORY_RETRIEVAL", "PLANNING", "CUSTOM", ]; if (type && !validTypes.includes(type)) { return NextResponse.json( { error: `Invalid type. Must be one of: ${validTypes.join(", ")}` }, { status: 400 } ); } // Validate sort const validSorts = ["newest", "oldest", "costliest"]; if (!validSorts.includes(sort)) { return NextResponse.json( { error: `Invalid sort. Must be one of: ${validSorts.join(", ")}` }, { status: 400 } ); } const where: Prisma.DecisionPointWhereInput = { trace: { userId: session.user.id }, }; if (type) { where.type = type as Prisma.EnumDecisionTypeFilter["equals"]; } if (search) { where.reasoning = { contains: search, mode: "insensitive", }; } // Build order by let orderBy: Prisma.DecisionPointOrderByWithRelationInput; switch (sort) { case "oldest": orderBy = { timestamp: "asc" }; break; case "costliest": orderBy = { costUsd: "desc" }; break; case "newest": default: orderBy = { timestamp: "desc" }; break; } // Count total const total = await prisma.decisionPoint.count({ where }); // Pagination const skip = (page - 1) * limit; const totalPages = Math.ceil(total / limit); // Fetch decisions with parent trace and span const decisions = await prisma.decisionPoint.findMany({ where, include: { trace: { select: { id: true, name: true, }, }, span: { select: { id: true, name: true, }, }, }, orderBy, skip, take: limit, }); return NextResponse.json( { decisions, total, page, limit, totalPages, }, { status: 200 } ); } catch (error) { console.error("Error listing decisions:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }