158 lines
4.0 KiB
JavaScript
158 lines
4.0 KiB
JavaScript
import { graphUpdateSchema } from "./schema.js";
|
|
|
|
const TOP_LEVEL_ARRAY_FIELDS = [
|
|
"addedNodes",
|
|
"updatedNodes",
|
|
"addedEdges",
|
|
"removedEdgeIds",
|
|
"resolvedUnknownNodeIds",
|
|
"affectedNodeIds",
|
|
];
|
|
|
|
const TOP_LEVEL_NULLABLE_FIELDS = ["selectedQuestion"];
|
|
|
|
function cloneJsonSafe(value) {
|
|
if (value == null) return value;
|
|
return JSON.parse(JSON.stringify(value));
|
|
}
|
|
|
|
function removeNullArrayEntries(value, path = [], normalisationsApplied = []) {
|
|
if (Array.isArray(value)) {
|
|
const filtered = [];
|
|
value.forEach((item, index) => {
|
|
if (item === null) {
|
|
normalisationsApplied.push({
|
|
path: [...path, index],
|
|
change: "Removed null array entry",
|
|
});
|
|
return;
|
|
}
|
|
filtered.push(
|
|
removeNullArrayEntries(item, [...path, index], normalisationsApplied),
|
|
);
|
|
});
|
|
return filtered;
|
|
}
|
|
|
|
if (value && typeof value === "object") {
|
|
return Object.fromEntries(
|
|
Object.entries(value).map(([key, child]) => [
|
|
key,
|
|
removeNullArrayEntries(child, [...path, key], normalisationsApplied),
|
|
]),
|
|
);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function applyKnownEnumAliases(proposal, normalisationsApplied) {
|
|
if (!proposal || typeof proposal !== "object") return proposal;
|
|
|
|
if (Array.isArray(proposal.addedNodes)) {
|
|
proposal.addedNodes = proposal.addedNodes.map((node, index) => {
|
|
if (node?.kind === "reported_statement") {
|
|
normalisationsApplied.push({
|
|
path: ["addedNodes", index, "kind"],
|
|
change: "Converted reported_statement to reported_claim",
|
|
});
|
|
return { ...node, kind: "reported_claim" };
|
|
}
|
|
return node;
|
|
});
|
|
}
|
|
|
|
return proposal;
|
|
}
|
|
|
|
function fillMissingOptionalArrays(proposal, normalisationsApplied) {
|
|
if (!proposal || typeof proposal !== "object") return proposal;
|
|
|
|
for (const field of TOP_LEVEL_ARRAY_FIELDS) {
|
|
if (!(field in proposal)) {
|
|
proposal[field] = [];
|
|
normalisationsApplied.push({
|
|
path: [field],
|
|
change: "Filled missing optional array with []",
|
|
});
|
|
}
|
|
}
|
|
|
|
return proposal;
|
|
}
|
|
|
|
function fillMissingNullableFields(proposal, normalisationsApplied) {
|
|
if (!proposal || typeof proposal !== "object") return proposal;
|
|
|
|
for (const field of TOP_LEVEL_NULLABLE_FIELDS) {
|
|
if (!(field in proposal)) {
|
|
proposal[field] = null;
|
|
normalisationsApplied.push({
|
|
path: [field],
|
|
change: "Filled missing optional nullable field with null",
|
|
});
|
|
}
|
|
}
|
|
|
|
return proposal;
|
|
}
|
|
|
|
export function parseGraphUpdateProposal(rawResponse) {
|
|
const raw = rawResponse;
|
|
let parsed;
|
|
|
|
if (typeof rawResponse === "string") {
|
|
try {
|
|
parsed = JSON.parse(rawResponse);
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
proposal: null,
|
|
raw,
|
|
normalisationsApplied: [],
|
|
errors: [error.message || "Model response is not valid JSON"],
|
|
};
|
|
}
|
|
} else if (rawResponse && typeof rawResponse === "object") {
|
|
parsed = cloneJsonSafe(rawResponse);
|
|
} else {
|
|
return {
|
|
success: false,
|
|
proposal: null,
|
|
raw,
|
|
normalisationsApplied: [],
|
|
errors: ["Graph update proposal must be a JSON object or JSON string"],
|
|
};
|
|
}
|
|
|
|
const normalisationsApplied = [];
|
|
let normalised = removeNullArrayEntries(parsed, [], normalisationsApplied);
|
|
normalised = applyKnownEnumAliases(normalised, normalisationsApplied);
|
|
normalised = fillMissingOptionalArrays(normalised, normalisationsApplied);
|
|
normalised = fillMissingNullableFields(normalised, normalisationsApplied);
|
|
|
|
const parsedProposal = graphUpdateSchema.safeParse(normalised);
|
|
|
|
if (!parsedProposal.success) {
|
|
return {
|
|
success: false,
|
|
proposal: null,
|
|
raw,
|
|
normalisationsApplied,
|
|
errors: parsedProposal.error.issues.map((issue) => ({
|
|
path: issue.path,
|
|
message: issue.message,
|
|
code: issue.code,
|
|
})),
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
proposal: parsedProposal.data,
|
|
raw,
|
|
normalisationsApplied,
|
|
errors: [],
|
|
};
|
|
}
|