From 76c609690503adc11913362ac766bfd82b9a9337 Mon Sep 17 00:00:00 2001 From: robbond Date: Tue, 1 Sep 2026 13:24:37 +0100 Subject: [PATCH] fix(confidence-engine): resolve model for episode reasoning --- lib/graph/orchestrator.js | 17 +++++++++- tests/graph/episode-reasoning-seam.test.js | 38 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/graph/orchestrator.js b/lib/graph/orchestrator.js index c5974b4..e93ae35 100644 --- a/lib/graph/orchestrator.js +++ b/lib/graph/orchestrator.js @@ -1152,7 +1152,22 @@ export async function reconsiderCompletedEpisode(epiParams, deps = {}) { const startedAt = Date.now(); try { - modelName = deps.modelName ?? (deps.config ? deps.config.OLLAMA_MODEL : null) ?? getModelName?.() ?? null; + // Preserve original priority (deps.modelName > deps.config.OLLAMA_MODEL > getModelName) with assertConfig fallback only when no deps provide a model + let resolvedConfig = undefined; + if (deps.modelName == null && deps.config?.OLLAMA_MODEL == null && deps.config !== null) { + const hasOtherDeps = Object.keys(deps).some((k) => k !== "config" && k !== "modelName"); + if (hasOtherDeps) { + resolvedConfig = undefined; // don't call assertConfig when deps is non-empty with other keys + } else { + resolvedConfig = assertConfig(); + } + } + const config = deps.config ?? resolvedConfig; + modelName = + deps.modelName ?? + (config != null ? config.OLLAMA_MODEL : undefined) ?? + getModelName?.() ?? + null; const promptBuilder = buildEpisodePrompt ?? buildEpisodeAwareGraphPrompt; const prompt = promptBuilder({ episode }); diff --git a/tests/graph/episode-reasoning-seam.test.js b/tests/graph/episode-reasoning-seam.test.js index 153edb8..8c750e8 100644 --- a/tests/graph/episode-reasoning-seam.test.js +++ b/tests/graph/episode-reasoning-seam.test.js @@ -155,4 +155,42 @@ describe("episode reasoning seam (reconsiderCompletedEpisode)", () => { expect(TEST_EPISODE.situationGraph.nodes.length).toBe(1); }); + it("resolves configured model via assertConfig fallback when no deps model is injected", async () => { + // Set minimal env vars for assertConfig to succeed in this specific test + const prevBaseUrl = process.env.OLLAMA_BASE_URL; + const prevModel = process.env.OLLAMA_MODEL; + process.env.OLLAMA_BASE_URL = "http://localhost:11434"; + process.env.OLLAMA_MODEL = "test-model"; + + const modelCaptured = []; + const provider = { + generateReconstruction: vi.fn().mockImplementation((prompt, model) => { + modelCaptured.push(model); + return makeProposalResponse(); + }), + }; + + // Reset modules so assertConfig reads fresh env vars + await vi.resetModules(); + + const { reconsiderCompletedEpisode } = await import("@/lib/graph/orchestrator.js"); + // Empty deps — matches route.js call: reconsiderCompletedEpisode(prepared) + // The fix ensures assertConfig() provides a model instead of leaving it null + const result = await reconsiderCompletedEpisode( + { ...TEST_EPISODE, provider }, + {}, + ); + + expect(result.success).toBe(true); + expect(modelCaptured.length).toBe(1); + expect(modelCaptured[0]).not.toBeNull(); + expect(typeof modelCaptured[0]).toBe("string"); + + // Restore env + if (prevBaseUrl == null) delete process.env.OLLAMA_BASE_URL; + else process.env.OLLAMA_BASE_URL = prevBaseUrl; + if (prevModel == null) delete process.env.OLLAMA_MODEL; + else process.env.OLLAMA_MODEL = prevModel; + }); + });