fix(confidence-engine): retain successful provider path

This commit is contained in:
2026-09-05 17:12:31 +01:00
parent dabd9e2245
commit 46b9bd8b03
5 changed files with 34 additions and 3 deletions
+5
View File
@@ -73,6 +73,11 @@
- The detector fix remains unverified live; a subsequent HTTP 500 left the actually attempted provider path unobservable.
- Case-start failure diagnostics now preserve `providerApiPath` only when the provider reports an endpoint actually attempted during that request. The next step remains one production call.
## Successful provider-path observability
- The 502 live run at `dabd9e2` was PATH NOT OBSERVABLE ON FAILURE: provider path survived provider errors but not successful-provider/later-validation failures.
- Successful provider results now retain their factual attempted path through later reconstruction-validation failure diagnostics. This corrects only that observability seam; the next unknown remains one real `/api/cases/start` call establishing `/api/chat` versus `/api/generate`.
## Current product architecture
Three distinct routes, not a single page:
+16 -1
View File
@@ -72,11 +72,23 @@ export async function analyseScenario(scenario, opts = {}) {
// ── Call provider ──────────────────────────────────
const provider = getProvider();
let rawResponse;
let providerApiPath;
try {
rawResponse = await provider.generateReconstruction(
const providerResult = await provider.generateReconstruction(
promptObj.prompt,
OLLAMA_MODEL,
);
if (
providerResult &&
typeof providerResult === "object" &&
"response" in providerResult &&
"providerApiPath" in providerResult
) {
rawResponse = providerResult.response;
providerApiPath = providerResult.providerApiPath;
} else {
rawResponse = providerResult;
}
} catch (e) {
return buildErrorResponse(
e.message || "Provider error during analysis",
@@ -137,6 +149,7 @@ export async function analyseScenario(scenario, opts = {}) {
duration,
promptVersion,
compatibility,
providerApiPath,
);
}
@@ -219,6 +232,7 @@ function buildPartialResult(
duration,
version,
compatibility,
providerApiPath,
) {
let errors = [];
const validationIssues = error?.issues ?? [];
@@ -245,6 +259,7 @@ function buildPartialResult(
nextQuestion: undefined,
errors,
validationIssues,
providerApiPath,
...buildCompatibilityDiagnostics(compatibility),
};
}
+4 -1
View File
@@ -247,7 +247,10 @@ class OllamaLlmProvider {
// Step 5: Parse and return
// ================================================================
try {
return recoverJson(rawResponse);
return {
response: recoverJson(rawResponse),
providerApiPath: apiUsed,
};
} catch (e) {
if (e instanceof SyntaxError) {
const error = new Error(
+5 -1
View File
@@ -14,7 +14,7 @@ describe("OllamaLlmProvider chat capability detection", () => {
try {
const { getProvider } = await import("@/lib/llm/provider.js");
await getProvider().generateReconstruction("prompt", "configured-model");
const result = await getProvider().generateReconstruction("prompt", "configured-model");
expect(JSON.parse(fetchSpy.mock.calls[0][1].body)).toMatchObject({
model: "configured-model",
@@ -23,6 +23,10 @@ describe("OllamaLlmProvider chat capability detection", () => {
expect(fetchSpy.mock.calls[0][0]).toBe("http://ollama.test/api/chat");
expect(fetchSpy.mock.calls[1][0]).toBe("http://ollama.test/api/chat");
expect(fetchSpy.mock.calls[1][0]).not.toContain("/api/generate");
expect(result).toMatchObject({
response: {},
providerApiPath: "/api/chat",
});
} finally {
vi.unstubAllGlobals();
if (originalBaseUrl === undefined) delete process.env.OLLAMA_BASE_URL;
@@ -210,6 +210,8 @@ describe("analyseScenario compatibility", () => {
it("preserves nested validation issues and complete raw output on reconstruction failure", async () => {
mockGenerateReconstruction.mockResolvedValue({
providerApiPath: "/api/chat",
response: {
inputClassification: {
primaryType: "unexplained_change",
secondaryTypes: [],
@@ -239,6 +241,7 @@ describe("analyseScenario compatibility", () => {
reason: "reason",
expectedInformationValue: "high",
},
},
});
const { analyseScenario } = await import("@/lib/analysis.js");
@@ -253,6 +256,7 @@ describe("analyseScenario compatibility", () => {
code: "invalid_type",
message: "Required",
}));
expect(result.providerApiPath).toBe("/api/chat");
expect(result.errors).toContain("reconstruction: Required");
});