SPB Git

spb/search-box Public

Agentic web research engine — hypotheses, verbatim evidence, contradictions, sourced answers streamed live. Claude Opus 5 + Firecrawl + PostgreSQL.

TypeScript 76.9% CSS 18.7% SQL 2.1% JavaScript 1.8% Shell 0.5%
1.3 KB · 46 lines typescript
Raw Blame History
1/**2 * Search-box.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: apps/web/app/api/research/route.ts6 * Description: POST — start a research session; GET — list recent sessions.7 */89import { NextResponse } from "next/server";10import { sessions } from "@search-box/db";11import { ensureMigrated, startResearch } from "@/lib/runner";1213export const runtime = "nodejs";14export const dynamic = "force-dynamic";1516export async function POST(req: Request): Promise<NextResponse> {17  let body: unknown;18  try {19    body = await req.json();20  } catch {21    return NextResponse.json({ error: "invalid JSON body" }, { status: 400 });22  }23  const question =24    typeof body === "object" && body !== null && "question" in body25      ? String((body as { question: unknown }).question ?? "").trim()26      : "";27  if (question.length < 8 || question.length > 2000) {28    return NextResponse.json({ error: "question must be 8–2000 characters" }, { status: 400 });29  }30  const id = await startResearch(question);31  return NextResponse.json({ id }, { status: 201 });32}3334export async function GET(): Promise<NextResponse> {35  await ensureMigrated();36  const list = await sessions.list(30);37  return NextResponse.json({38    sessions: list.map((s) => ({39      id: s.id,40      question: s.question,41      status: s.status,42      createdAt: s.createdAt43    }))44  });45}46