// Socrates dock API. // // GET → returns { threadId, messages: [{ role, text, options? }] } for the // active thread on this project. // POST → body { text }. Sends a user turn (or "open" if text is empty), // invokes the LLM, persists user + assistant messages, returns the // new assistant turn. import { NextResponse } from "next/server"; import { getActiveThread, loadProject } from "../../../../../lib/db/repo"; import { sendUserTurn } from "../../../../../lib/llm/socrates"; import { validate } from "../../../../../lib/sysml/validate"; export async function GET(_req: Request, { params }: { params: Promise<{ projectId: string }> }) { const { projectId } = await params; // Touch loadProject so a missing project gets seeded (also creates the thread). await loadProject(projectId); const thread = await getActiveThread(projectId); if (!thread) return NextResponse.json({ error: "no active thread" }, { status: 404 }); return NextResponse.json({ threadId: thread.id, title: thread.title, messages: thread.messages.map(m => { try { const parsed = JSON.parse(m.content); return { id: m.id, role: m.role as "user" | "assistant", text: typeof parsed.text === "string" ? parsed.text : "", options: Array.isArray(parsed.options) ? parsed.options : undefined, createdAt: m.createdAt.toISOString(), }; } catch { return { id: m.id, role: m.role as "user" | "assistant", text: m.content, createdAt: m.createdAt.toISOString() }; } }), }); } export async function POST(req: Request, { params }: { params: Promise<{ projectId: string }> }) { const { projectId } = await params; let body: { text?: string }; try { body = await req.json(); } catch { return NextResponse.json({ error: "invalid json body" }, { status: 400 }); } // Make sure the project + thread exist const { model } = await loadProject(projectId); const issues = validate(model); let thread = await getActiveThread(projectId); if (!thread) { return NextResponse.json({ error: "no active thread to post to" }, { status: 404 }); } try { const result = await sendUserTurn({ threadId: thread.id, model, issues, userText: body.text ?? "", }); return NextResponse.json({ threadId: thread.id, assistant: { id: result.assistant.id, text: result.assistant.turn.text, options: result.assistant.turn.options, createdAt: result.assistant.createdAt.toISOString(), }, user: result.user.id !== "(skipped)" ? { id: result.user.id, createdAt: result.user.createdAt.toISOString(), } : null, meta: { provider: result.assistant.provider, model: result.assistant.model, inputTokens: result.assistant.inputTokens, outputTokens: result.assistant.outputTokens, }, }); } catch (err) { return NextResponse.json({ error: (err as Error).message }, { status: 500 }); } }