feat: add graph update proposal orchestration

This commit is contained in:
2026-08-02 08:15:54 +01:00
parent b38a6a9f2e
commit f3cdfce0b0
2 changed files with 452 additions and 4 deletions
+127 -1
View File
@@ -4,12 +4,17 @@
*/
import { analyseScenario } from "../analysis.js";
import { assertConfig } from "../config.js";
import { getProvider } from "../llm/provider.js";
import {
makeGraph,
startCaseRequestSchema,
situationGraphSchema,
updateCaseRequestSchema,
} from "./schema.js";
import { buildInitialGraph, describeGraph } from "./builder.js";
import { buildGraphUpdatePrompt } from "./prompt-builder.js";
import { parseGraphUpdateProposal } from "./update-proposal.js";
import {
selectActiveUnknownCandidate,
validateGraphReferences,
@@ -124,5 +129,126 @@ export async function startCase(body) {
}
export async function updateCase() {
throw new Error("updateCase is not implemented yet");
return updateCaseWithDependencies(...arguments);
}
function sanitiseErrorMessage(error, fallbackMessage) {
if (typeof error?.message === "string" && error.message.trim().length > 0) {
return error.message;
}
return fallbackMessage;
}
async function updateCaseWithDependencies(body, dependencies = {}) {
const parsedRequest = updateCaseRequestSchema.safeParse(body);
if (!parsedRequest.success) {
return {
success: false,
stage: "request_validation",
error: "Invalid update-case request",
validationErrors: toValidationErrors(parsedRequest.error),
statusCode: 400,
};
}
const { situationGraph, previousQuestion, answer, promptVersion } =
parsedRequest.data;
const graphSchemaValidation = situationGraphSchema.safeParse(situationGraph);
const graphReferenceValidation = validateGraphReferences(situationGraph);
if (!graphSchemaValidation.success || !graphReferenceValidation.valid) {
return {
success: false,
stage: "graph_validation",
error: "Invalid situation graph",
graphValidationErrors: [
...(!graphSchemaValidation.success
? toValidationErrors(graphSchemaValidation.error)
: []),
...(!graphReferenceValidation.valid
? graphReferenceValidation.errors
: []),
],
statusCode: 400,
};
}
const buildPrompt =
dependencies.buildGraphUpdatePrompt ?? buildGraphUpdatePrompt;
const parseProposal =
dependencies.parseGraphUpdateProposal ?? parseGraphUpdateProposal;
let modelName = null;
let rawResponse;
const startedAt = Date.now();
try {
const config = dependencies.config ?? assertConfig();
modelName = config.OLLAMA_MODEL;
const prompt = buildPrompt({
situationGraph,
previousQuestion,
answer,
promptVersion,
});
const provider = dependencies.provider ?? getProvider();
rawResponse = await provider.generateReconstruction(prompt, modelName);
} catch (error) {
return {
success: false,
stage: "provider",
error: "Graph update proposal generation failed",
providerErrors: [
sanitiseErrorMessage(
error,
"Provider failed to generate graph update proposal",
),
],
diagnostics: {
promptVersion: promptVersion ?? null,
modelName,
responseDurationMs: Date.now() - startedAt,
normalisationsApplied: [],
},
statusCode: 502,
};
}
const parsedProposal = parseProposal(rawResponse);
const responseDurationMs = Date.now() - startedAt;
if (!parsedProposal.success) {
return {
success: false,
stage: "proposal_validation",
error: "Invalid graph update proposal",
proposalErrors: parsedProposal.errors,
diagnostics: {
promptVersion: promptVersion ?? null,
modelName,
responseDurationMs,
normalisationsApplied: parsedProposal.normalisationsApplied,
},
statusCode: 502,
};
}
return {
success: true,
stage: "proposal_ready",
proposal: parsedProposal.proposal,
diagnostics: {
promptVersion: promptVersion ?? null,
modelName,
responseDurationMs,
normalisationsApplied: parsedProposal.normalisationsApplied,
graphNodeCount: situationGraph.nodes.length,
graphEdgeCount: situationGraph.edges.length,
},
};
}