wip(confidence-engine): checkpoint open-question presentation work
This commit is contained in:
+136
-1
@@ -8,7 +8,11 @@ import {
|
||||
normaliseOpenAITransportResponse,
|
||||
reconstructionJsonSchema,
|
||||
} from "@/lib/llm/provider.js";
|
||||
import { reconstructionV2Schema } from "@/lib/reconstruction/schema.js";
|
||||
import {
|
||||
reconstructionGenerationJsonSchema,
|
||||
reconstructionGenerationSchema,
|
||||
reconstructionV2Schema,
|
||||
} from "@/lib/reconstruction/schema.js";
|
||||
import { focusedDeconstructJsonSchema } from "@/lib/graph/focused-investigation.js";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -299,6 +303,137 @@ describe("OpenAI reconstruction provider experiment seam", () => {
|
||||
expect(acceptsNull(transition.properties.id)).toBe(false);
|
||||
});
|
||||
|
||||
it("preserves optional transport nullability for the generation-specific schema", async () => {
|
||||
const fetchImpl = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ output_text: "{}" }),
|
||||
});
|
||||
const provider = createOpenAIReconstructionProvider({
|
||||
apiKey: "test-key",
|
||||
fetchImpl,
|
||||
});
|
||||
|
||||
await provider.generateReconstruction(
|
||||
"prompt",
|
||||
"test-model",
|
||||
reconstructionGenerationJsonSchema,
|
||||
{ outputZodSchema: reconstructionGenerationSchema },
|
||||
);
|
||||
|
||||
const request = JSON.parse(fetchImpl.mock.calls[0][1].body);
|
||||
const reconstruction = request.text.format.schema.properties.reconstruction;
|
||||
const unknown = reconstruction.properties.importantUnknowns.items;
|
||||
const unexplained = reconstruction.properties.unexplainedTransitions.items;
|
||||
|
||||
expect(unknown.required).toContain("question");
|
||||
expect(unknown.properties.question.minLength).toBe(1);
|
||||
expect(unexplained.required).toContain("entity");
|
||||
expect(unexplained.properties.entity.anyOf).toContainEqual({ type: "null" });
|
||||
});
|
||||
|
||||
it("normalises generation-schema null placeholders before canonical validation", async () => {
|
||||
const transportResponse = {
|
||||
inputClassification: {
|
||||
primaryType: "unexplained_change",
|
||||
secondaryTypes: null,
|
||||
reasoningModes: null,
|
||||
classificationReason: "A reported change requires reconstruction.",
|
||||
confidence: "high",
|
||||
},
|
||||
reconstruction: {
|
||||
summary: "A change occurred and its cause remains uncertain.",
|
||||
actors: [],
|
||||
systemsOrObjects: [],
|
||||
expectedStates: [],
|
||||
observedStates: [],
|
||||
differences: [],
|
||||
knownTransitions: [],
|
||||
unexplainedTransitions: [
|
||||
{
|
||||
id: "transition-1",
|
||||
description: "The service level declined after the release.",
|
||||
confidence: "medium",
|
||||
entity: null,
|
||||
previousState: null,
|
||||
currentState: null,
|
||||
},
|
||||
],
|
||||
contradictions: [],
|
||||
importantUnknowns: [
|
||||
{
|
||||
id: "unknown-1",
|
||||
description: "Whether the release caused the service-level decline",
|
||||
question: "Did the release cause the service-level decline?",
|
||||
confidence: "medium",
|
||||
},
|
||||
],
|
||||
plausibleInterpretations: [
|
||||
{
|
||||
id: "interpretation-1",
|
||||
description: "The release may have reduced service capacity.",
|
||||
supportingEvidenceIds: ["evidence-1"],
|
||||
assumptionsRequired: null,
|
||||
confidence: "low",
|
||||
},
|
||||
],
|
||||
relationships: null,
|
||||
},
|
||||
evidence: [
|
||||
{
|
||||
id: "evidence-1",
|
||||
description: "The decline was reported after the release.",
|
||||
evidenceType: "reported_statement",
|
||||
source: null,
|
||||
attribution: null,
|
||||
confidence: "medium",
|
||||
importance: "important",
|
||||
},
|
||||
],
|
||||
nextQuestion: {
|
||||
id: "next-1",
|
||||
question: "What changed in service capacity after the release?",
|
||||
targets: ["unknown-1"],
|
||||
reason: "The cause of the decline remains unresolved.",
|
||||
expectedInformationValue: "high",
|
||||
reasoningMode: null,
|
||||
},
|
||||
};
|
||||
const fetchImpl = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ output_text: JSON.stringify(transportResponse) }),
|
||||
});
|
||||
const provider = createOpenAIReconstructionProvider({
|
||||
apiKey: "test-key",
|
||||
fetchImpl,
|
||||
});
|
||||
|
||||
const result = await provider.generateReconstruction(
|
||||
"prompt",
|
||||
"test-model",
|
||||
reconstructionGenerationJsonSchema,
|
||||
{ outputZodSchema: reconstructionGenerationSchema },
|
||||
);
|
||||
const request = JSON.parse(fetchImpl.mock.calls[0][1].body);
|
||||
const unexplainedSchema =
|
||||
request.text.format.schema.properties.reconstruction.properties
|
||||
.unexplainedTransitions.items;
|
||||
|
||||
expect(unexplainedSchema.required).toContain("entity");
|
||||
expect(unexplainedSchema.properties.entity.anyOf).toContainEqual({ type: "null" });
|
||||
expect(result.response.inputClassification).not.toHaveProperty("secondaryTypes");
|
||||
expect(result.response.inputClassification).not.toHaveProperty("reasoningModes");
|
||||
expect(result.response.reconstruction.unexplainedTransitions[0]).not.toHaveProperty("entity");
|
||||
expect(result.response.reconstruction.unexplainedTransitions[0]).not.toHaveProperty("previousState");
|
||||
expect(result.response.reconstruction.unexplainedTransitions[0]).not.toHaveProperty("currentState");
|
||||
expect(result.response.reconstruction.plausibleInterpretations[0]).not.toHaveProperty("assumptionsRequired");
|
||||
expect(result.response.reconstruction).not.toHaveProperty("relationships");
|
||||
expect(result.response.evidence[0]).not.toHaveProperty("source");
|
||||
expect(result.response.evidence[0].attribution).toBeNull();
|
||||
expect(result.response.nextQuestion).not.toHaveProperty("reasoningMode");
|
||||
expect(reconstructionGenerationSchema.safeParse(result.response).success).toBe(true);
|
||||
expect(reconstructionV2Schema.safeParse(result.response).success).toBe(true);
|
||||
});
|
||||
|
||||
it("removes only optional transport null placeholders", () => {
|
||||
const schema = z.object({
|
||||
optionalText: z.string().optional(),
|
||||
|
||||
Reference in New Issue
Block a user