Files
confidence-engine/app/api/focused-investigation/deconstruct/route.js
T
robbond 01c57788ee feat(confidence-engine): stabilize user-directed investigation flow
Intentional changes in this checkpoint:
- Deconstruct route: use body.targetNodeId (client identity) over raw.model-invented ID
- ThreadContributionsBadge: compact per-thread contribution indicator with expandable history
- Reopen continuation: resume from accumulated contributions instead of reformulating
- showEvidenceLimit gate: hide evidence-limit card during active investigation paths
- Evidence-limit visibility correction in rendering pipeline
- Section ordering: assumptions and connections after 'Still unclear' in focused result
- Prompt v0.3: preserve user-stated alternatives as separate unknowns; no count inflation
- 3 durable regression tests (target identity, contribution persistence, reopen state)
- evidence-limit card visibility gate test suite

Temporary residue removed:
- test-analysis.mjs (scratch diagnostic)
- 5 diagnostic console.log blocks from reasoning-workspace.jsx
2026-08-23 12:05:51 +01:00

90 lines
2.8 KiB
JavaScript

import { getProvider } from "@/lib/llm/provider";
import { buildFocusedDeconstructPrompt, validateFocusedDeconstructSchema } from "@/lib/graph/focused-investigation";
export async function POST(request) {
try {
const body = await request.json();
if (!body.targetNodeId || typeof body.targetNodeId !== "string") {
return Response.json(
{ error: "Request must include a 'targetNodeId' string field" },
{ status: 400 },
);
}
if (!body.targetLabel || typeof body.targetLabel !== "string") {
return Response.json(
{ error: "Request must include a 'targetLabel' string field" },
{ status: 400 },
);
}
if (!body.targetDescription || typeof body.targetDescription !== "string") {
return Response.json(
{ error: "Request must include a 'targetDescription' string field" },
{ status: 400 },
);
}
if (!body.centralStatement || typeof body.centralStatement !== "string") {
return Response.json(
{ error: "Request must include a 'centralStatement' string field" },
{ status: 400 },
);
}
if (!body.question || typeof body.question !== "string") {
return Response.json(
{ error: "Request must include a 'question' string field" },
{ status: 400 },
);
}
if (!body.answer || typeof body.answer !== "string") {
return Response.json(
{ error: "Request must include an 'answer' string field" },
{ status: 400 },
);
}
const prompt = buildFocusedDeconstructPrompt({
targetLabel: body.targetLabel,
targetDescription: body.targetDescription,
centralStatement: body.centralStatement,
question: body.question,
answer: body.answer,
});
const provider = getProvider();
const startedAt = Date.now();
const raw = await provider.generateReconstruction(prompt, process.env.OLLAMA_MODEL);
const elapsedMs = Date.now() - startedAt;
// Validate schema (required fields present, no graph-mutation fields)
const validationErrors = validateFocusedDeconstructSchema(raw);
if (validationErrors.length > 0) {
return Response.json(
{
success: false,
error: "Focused deconstruction result did not match expected schema",
validationErrors,
targetNodeId: body.targetNodeId,
elapsedMs,
},
{ status: 502 },
);
}
return Response.json({
success: true,
targetNodeId: body.targetNodeId,
observations: raw.observations,
uncertainties: raw.uncertainties,
assumptions: raw.assumptions,
relationships: raw.relationships,
possibleFollowUpQuestions: raw.possibleFollowUpQuestions,
elapsedMs,
});
} catch (e) {
return Response.json(
{ error: e.message || "Unknown server error" },
{ status: 500 },
);
}
}