fix: align sync fallback chain, fix model-fallback test determinism

- Hoist resolveFallbackChainForCallOmoAgent before sync/background branch
  so sync executor also receives the fallback chain
- Add fallbackChain parameter to sync-executor with setSessionFallbackChain
- Mock connected-providers-cache in event.model-fallback tests for
  deterministic behavior (no dependency on local cache files)
- Update test expectations to account for no-op fallback skip when
  normalized current model matches first fallback entry
- Add cache spy isolation for subagent-resolver fallback_models tests
This commit is contained in:
YeonGyu-Kim
2026-03-09 13:11:03 +09:00
parent c598afa521
commit 7d1607dc16
5 changed files with 92 additions and 20 deletions
+17 -13
View File
@@ -1,10 +1,15 @@
import { afterEach, describe, expect, test } from "bun:test"
declare const require: (name: string) => any
const { afterEach, describe, expect, mock, test } = require("bun:test")
mock.module("../shared/connected-providers-cache", () => ({
readConnectedProvidersCache: () => null,
readProviderModelsCache: () => null,
}))
import { createEventHandler } from "./event"
import { createChatMessageHandler } from "./chat-message"
import { _resetForTesting, setMainSession } from "../features/claude-code-session-state"
import { createModelFallbackHook, clearPendingModelFallback } from "../hooks/model-fallback/hook"
describe("createEventHandler - model fallback", () => {
const createHandler = (args?: { hooks?: any; pluginConfig?: any }) => {
const abortCalls: string[] = []
@@ -207,10 +212,10 @@ describe("createEventHandler - model fallback", () => {
expect(abortCalls).toEqual([sessionID])
expect(promptCalls).toEqual([sessionID])
expect(output.message["model"]).toMatchObject({
modelID: "claude-opus-4-6",
providerID: "kimi-for-coding",
modelID: "k2p5",
})
expect(["anthropic", "quotio", "opencode"]).toContain((output.message["model"] as { providerID?: string })?.providerID)
expect(output.message["variant"]).toBe("max")
expect(output.message["variant"]).toBeUndefined()
})
test("does not spam abort/prompt when session.status retry countdown updates", async () => {
@@ -533,20 +538,19 @@ describe("createEventHandler - model fallback", () => {
//#when - first retry cycle
const first = await triggerRetryCycle()
//#then - first fallback entry applied (prefers current provider when available)
//#then - first fallback entry applied (no-op skip: claude-opus-4-6 matches current model after normalization)
expect(first.message["model"]).toMatchObject({
modelID: "claude-opus-4-6",
providerID: "kimi-for-coding",
modelID: "k2p5",
})
expect(["anthropic", "quotio", "opencode"]).toContain((first.message["model"] as { providerID?: string })?.providerID)
expect(first.message["variant"]).toBe("max")
expect(first.message["variant"]).toBeUndefined()
//#when - second retry cycle
const second = await triggerRetryCycle()
//#then - second fallback entry applied (chain advanced)
expect(second.message["model"]).toEqual({
providerID: "kimi-for-coding",
modelID: "k2p5",
//#then - second fallback entry applied (chain advanced past k2p5)
expect(second.message["model"]).toMatchObject({
modelID: "kimi-k2.5",
})
expect((second.message["model"] as { providerID?: string })?.providerID).toBeTruthy()
expect(second.message["variant"]).toBeUndefined()