fix(confidence-engine): retain successful provider path
This commit is contained in:
@@ -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
@@ -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
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user