129 lines
3.5 KiB
JavaScript
129 lines
3.5 KiB
JavaScript
/**
|
|
* Situation Graph Case Orchestrator — manages the lifecycle of a case.
|
|
* startCase builds initial graph from analysis; updateCase applies answers.
|
|
*/
|
|
|
|
import { analyseScenario } from "../analysis.js";
|
|
import {
|
|
makeGraph,
|
|
startCaseRequestSchema,
|
|
situationGraphSchema,
|
|
} from "./schema.js";
|
|
import { buildInitialGraph, describeGraph } from "./builder.js";
|
|
import {
|
|
selectActiveUnknownCandidate,
|
|
validateGraphReferences,
|
|
} from "./utils.js";
|
|
|
|
function toValidationErrors(error) {
|
|
return (
|
|
error?.errors?.map((issue) => ({
|
|
path: issue.path,
|
|
message: issue.message,
|
|
code: issue.code,
|
|
})) ?? [{ message: "Validation failed" }]
|
|
);
|
|
}
|
|
|
|
function buildDiagnostics({ analysis, graph, graphReferenceValidation }) {
|
|
return {
|
|
promptVersion: analysis?.promptVersion ?? null,
|
|
modelName: analysis?.modelName ?? null,
|
|
responseDurationMs: analysis?.responseDurationMs ?? null,
|
|
validationStatus: analysis?.validationStatus ?? "invalid",
|
|
nodeCount: graph?.nodes?.length ?? 0,
|
|
edgeCount: graph?.edges?.length ?? 0,
|
|
graphReferenceValidation,
|
|
compatibilityApplied: analysis?.compatibilityApplied ?? false,
|
|
compatibilityChanges: analysis?.compatibilityChanges ?? [],
|
|
compatibilityWarnings: analysis?.compatibilityWarnings ?? [],
|
|
};
|
|
}
|
|
|
|
export async function startCase(body) {
|
|
const parsedRequest = startCaseRequestSchema.safeParse(body);
|
|
|
|
if (!parsedRequest.success) {
|
|
return {
|
|
success: false,
|
|
error: "Invalid start-case request",
|
|
validationErrors: toValidationErrors(parsedRequest.error),
|
|
statusCode: 400,
|
|
};
|
|
}
|
|
|
|
const { scenario, promptVersion } = parsedRequest.data;
|
|
const analysis = await analyseScenario(scenario, { promptVersion });
|
|
|
|
if (!analysis.success) {
|
|
return {
|
|
success: false,
|
|
error: analysis.error ?? "Scenario analysis failed",
|
|
diagnostics: buildDiagnostics({
|
|
analysis,
|
|
graph: null,
|
|
graphReferenceValidation: null,
|
|
}),
|
|
analysisErrors: analysis.errors ?? undefined,
|
|
rawResponse: analysis.rawResponse ?? undefined,
|
|
statusCode: Number(analysis.statusCode) || 502,
|
|
};
|
|
}
|
|
|
|
const initialGraph = buildInitialGraph({
|
|
reconstruction: analysis.reconstruction,
|
|
evidence: analysis.evidence,
|
|
});
|
|
|
|
const currentSummary = describeGraph(initialGraph);
|
|
const activeUnknownNodeId =
|
|
selectActiveUnknownCandidate(
|
|
{
|
|
...initialGraph,
|
|
resolvedNodeIds: [],
|
|
},
|
|
[],
|
|
)?.nodeId ?? null;
|
|
|
|
const situationGraph = makeGraph({
|
|
centralStatement: scenario,
|
|
nodes: initialGraph.nodes,
|
|
edges: initialGraph.edges,
|
|
activeUnknownNodeId,
|
|
resolvedNodeIds: [],
|
|
currentSummary,
|
|
});
|
|
|
|
situationGraphSchema.parse(situationGraph);
|
|
|
|
const graphReferenceValidation = validateGraphReferences(situationGraph);
|
|
if (!graphReferenceValidation.valid) {
|
|
return {
|
|
success: false,
|
|
error: "Situation graph reference validation failed",
|
|
diagnostics: buildDiagnostics({
|
|
analysis,
|
|
graph: situationGraph,
|
|
graphReferenceValidation,
|
|
}),
|
|
validationErrors: graphReferenceValidation.errors,
|
|
statusCode: 500,
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
situationGraph,
|
|
selectedQuestion: analysis.nextQuestion ?? null,
|
|
diagnostics: buildDiagnostics({
|
|
analysis,
|
|
graph: situationGraph,
|
|
graphReferenceValidation,
|
|
}),
|
|
};
|
|
}
|
|
|
|
export async function updateCase() {
|
|
throw new Error("updateCase is not implemented yet");
|
|
}
|