fix(model-resolver): skip fallback chain when no cache exists
When no provider cache exists, skip the fallback chain entirely and let OpenCode use Provider.defaultModel() as the final fallback. This prevents incorrect model selection when the plugin loads before providers connect. - Remove forced first-entry fallback when no cache - Add log messages for cache miss scenarios - Update tests for new behavior
This commit is contained in:
+42
-10
@@ -1,7 +1,8 @@
|
||||
import { describe, test, expect, beforeEach } from "bun:test"
|
||||
import { describe, test, expect, beforeEach, spyOn, afterEach } from "bun:test"
|
||||
import { createBuiltinAgents } from "./utils"
|
||||
import type { AgentConfig } from "@opencode-ai/sdk"
|
||||
import { clearSkillCache } from "../features/opencode-skill-loader/skill-content"
|
||||
import * as connectedProvidersCache from "../shared/connected-providers-cache"
|
||||
|
||||
const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-5"
|
||||
|
||||
@@ -46,17 +47,32 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
|
||||
})
|
||||
|
||||
test("Oracle uses first fallback entry when no availableModels provided (no cache scenario)", async () => {
|
||||
// #given - no available models simulates CI without model cache
|
||||
test("Oracle uses connected provider when no availableModels but connected cache exists", async () => {
|
||||
// #given - connected providers cache exists with openai
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
|
||||
|
||||
// #when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - uses first fallback entry (openai/gpt-5.2) instead of system default
|
||||
// #then - uses openai from connected cache
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2")
|
||||
expect(agents.oracle.reasoningEffort).toBe("medium")
|
||||
expect(agents.oracle.textVerbosity).toBe("high")
|
||||
expect(agents.oracle.thinking).toBeUndefined()
|
||||
cacheSpy.mockRestore()
|
||||
})
|
||||
|
||||
test("Oracle created without model field when no cache exists (first run scenario)", async () => {
|
||||
// #given - no cache at all (first run)
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
|
||||
|
||||
// #when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - oracle should be created with system default model (fallback to systemDefaultModel)
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.model).toBe(TEST_DEFAULT_MODEL)
|
||||
cacheSpy.mockRestore()
|
||||
})
|
||||
|
||||
test("Oracle with GPT model override has reasoningEffort, no thinking", async () => {
|
||||
@@ -107,26 +123,42 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
})
|
||||
|
||||
describe("createBuiltinAgents without systemDefaultModel", () => {
|
||||
test("creates agents successfully without systemDefaultModel", async () => {
|
||||
// #given - no systemDefaultModel provided
|
||||
test("creates agents with connected provider when cache exists", async () => {
|
||||
// #given - connected providers cache exists
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
|
||||
|
||||
// #when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then - agents should still be created using fallback chain
|
||||
// #then - agents should use connected provider from fallback chain
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2")
|
||||
cacheSpy.mockRestore()
|
||||
})
|
||||
|
||||
test("sisyphus uses fallback chain when systemDefaultModel undefined", async () => {
|
||||
// #given - no systemDefaultModel
|
||||
test("agents NOT created when no cache and no systemDefaultModel (first run without defaults)", async () => {
|
||||
// #given - no cache and no system default
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
|
||||
|
||||
// #when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then - sisyphus should use its fallback chain
|
||||
// #then - oracle should NOT be created (resolveModelWithFallback returns undefined)
|
||||
expect(agents.oracle).toBeUndefined()
|
||||
cacheSpy.mockRestore()
|
||||
})
|
||||
|
||||
test("sisyphus uses connected provider when cache exists", async () => {
|
||||
// #given - connected providers cache exists with anthropic
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
|
||||
|
||||
// #when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then - sisyphus should use anthropic from connected cache
|
||||
expect(agents.sisyphus).toBeDefined()
|
||||
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||
cacheSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user