Files
confidence-engine/app/api/focused-investigation/formulate/route.js
T

104 lines
3.4 KiB
JavaScript

import { getProvider, getProviderModelName } from "@/lib/llm/provider";
import {
assessStrategyCompatibility,
formulateQuestionForTarget,
isStrategyQuestionTemplateCompatible,
} from "@/lib/graph/focused-investigation";
import { withAuthenticatedApi } from "@/lib/supabase/api-auth.js";
const STRATEGY_ASSESSMENT_TIMEOUT_MS = 10000;
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.situationGraph || typeof body.situationGraph !== "object") {
return Response.json(
{ error: "Request must include a 'situationGraph' object field" },
{ status: 400 },
);
}
const proposed = formulateQuestionForTarget({
situationGraph: body.situationGraph,
targetNodeId: body.targetNodeId,
});
if (!proposed.success) {
return Response.json(
{ success: false, error: proposed.error },
{ status: 400 },
);
}
let result = proposed;
if (proposed.investigationStrategy) {
const controller = new AbortController();
const timeout = setTimeout(
() => controller.abort(),
STRATEGY_ASSESSMENT_TIMEOUT_MS,
);
let strategyCompatibilityVerdict = {
strategyKey: proposed.investigationStrategy.key,
relevance: "unavailable",
};
try {
const assessment = await assessStrategyCompatibility({
provider: getProvider(),
modelName: getProviderModelName(),
targetLabel: body.situationGraph.nodes.find((node) => node.id === body.targetNodeId)?.label,
targetDescription: body.situationGraph.nodes.find((node) => node.id === body.targetNodeId)?.description,
centralStatement: body.situationGraph.centralStatement,
proposedStrategy: proposed.investigationStrategy,
signal: controller.signal,
});
if (assessment.success) strategyCompatibilityVerdict = assessment.verdict;
} catch {
// A timed-out or unavailable assessment is explicitly non-authorizing.
} finally {
clearTimeout(timeout);
}
result = formulateQuestionForTarget({
situationGraph: body.situationGraph,
targetNodeId: body.targetNodeId,
strategyCompatibilityVerdict,
strategyTemplateCompatibility:
strategyCompatibilityVerdict.relevance === "compatible" &&
!isStrategyQuestionTemplateCompatible(proposed.investigationStrategy)
? "incompatible"
: undefined,
});
}
return Response.json({
success: true,
targetNodeId: result.targetNodeId,
question: result.question,
strategy: result.strategy,
reasoningPattern: result.reasoningPattern,
reasoningPatternReason: result.reasoningPatternReason,
reason: result.reason,
questionFamily: result.questionFamily,
selectedQuestionTemplate: result.selectedQuestionTemplate,
allowedQuestionFamilies: result.allowedQuestionFamilies,
rejectedQuestionFamilies: result.rejectedQuestionFamilies,
});
} catch (e) {
return Response.json(
{ error: e.message || "Unknown server error" },
{ status: 500 },
);
}
}
export const POST = withAuthenticatedApi(post);