diff --git a/app/api/focused-investigation/deconstruct/route.js b/app/api/focused-investigation/deconstruct/route.js index 32a0cd4..e9ce041 100644 --- a/app/api/focused-investigation/deconstruct/route.js +++ b/app/api/focused-investigation/deconstruct/route.js @@ -50,6 +50,23 @@ async function post(request) { ); } + const REQUEST_LENGTH_LIMITS = { + answer: 10000, + question: 2048, + centralStatement: 2048, + targetLabel: 2048, + targetDescription: 2048, + }; + + for (const [field, limit] of Object.entries(REQUEST_LENGTH_LIMITS)) { + if (body[field] && body[field].length > limit) { + return Response.json( + { error: `Request field "${field}" exceeds maximum length of ${limit} characters` }, + { status: 400 }, + ); + } + } + const prompt = buildFocusedDeconstructPrompt({ targetLabel: body.targetLabel, targetDescription: body.targetDescription, diff --git a/components/reasoning-workspace.jsx b/components/reasoning-workspace.jsx index 9d4a0e7..647d83a 100644 --- a/components/reasoning-workspace.jsx +++ b/components/reasoning-workspace.jsx @@ -30,6 +30,9 @@ function isTechnicalSummary(summary) { return false; } +// ── Focused answer contract ────────────────────────────────── +const FOCUSED_ANSWER_MAX_LENGTH = 10000; + // ── Recovery state components (Phase 2) ─────────────────────── function ProviderUnavailableCard({ onRestart }) { @@ -238,8 +241,11 @@ function FocusedQuestionBody({ {focused?.question?.trim() && processingStep !== "active" && focused.status === "formulated" && !hasAnswer && !hasActiveFollowUp && (
-