From ceadf4bdbc5f1acf0d13ea7c152ef9fbc1c7ebfc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:30:02 +0900 Subject: [PATCH] fix(cli): prefer mini-fast for install fallback Default the install-time fallback chain to gpt-5.4-mini-fast for librarian and explore when OpenAI is available.\nKeep the snapshot and catalog tests aligned with the new resolution path. Co-authored-by: Sisyphus --- .../__snapshots__/model-fallback.test.ts.snap | 150 ++++++++++-------- src/cli/model-fallback.test.ts | 24 +-- src/cli/model-fallback.ts | 8 +- src/cli/openai-only-model-catalog.test.ts | 6 +- 4 files changed, 103 insertions(+), 85 deletions(-) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index dc2bac7a6..ce9ea35df 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -519,12 +519,31 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "model": "anthropic/claude-haiku-4-5", + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -718,12 +737,31 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "model": "anthropic/claude-haiku-4-5", + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -917,10 +955,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -1142,10 +1177,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -1369,11 +1401,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1555,11 +1582,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1869,14 +1891,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen }, "explore": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "anthropic/claude-haiku-4-5", @@ -2153,10 +2172,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", + "model": "openai/gpt-5.4-nano", }, ], - "model": "github-copilot/gpt-5-mini", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -2168,6 +2187,14 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -2622,13 +2649,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -2645,14 +2666,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "zai-coding-plan/glm-4.7", @@ -3020,19 +3038,19 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3050,9 +3068,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "anthropic/claude-haiku-4-5", }, @@ -3060,10 +3075,13 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ @@ -3571,19 +3589,19 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3601,9 +3619,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "anthropic/claude-haiku-4-5", }, @@ -3611,10 +3626,13 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ @@ -4120,9 +4138,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4130,7 +4145,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4148,7 +4163,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", @@ -4413,9 +4428,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4423,7 +4435,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4441,7 +4453,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index 67fa83fd7..5d6d2915a 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -553,15 +553,15 @@ describe("generateModelConfig", () => { }) describe("special-case agents include fallback_models", () => { - test("explore includes fallback_models when Copilot and Claude are both available", () => { - // #given both Copilot and Claude are available - const config = createConfig({ hasCopilot: true, hasClaude: true }) + test("explore includes fallback_models when OpenAI and Claude are both available", () => { + // #given both OpenAI and Claude are available + const config = createConfig({ hasOpenAI: true, hasClaude: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then explore should have fallback_models from the remaining chain entries - expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") + expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.explore?.fallback_models).toBeDefined() expect(result.agents?.explore?.fallback_models?.length).toBeGreaterThan(0) }) @@ -578,28 +578,28 @@ describe("generateModelConfig", () => { expect(result.agents?.explore?.fallback_models).toBeUndefined() }) - test("librarian includes fallback_models when opencode-go and Claude are both available", () => { - // #given opencode-go and Claude are available - const config = createConfig({ hasOpencodeGo: true, hasClaude: true }) + test("librarian includes fallback_models when OpenAI and opencode-go are both available", () => { + // #given OpenAI and opencode-go are available + const config = createConfig({ hasOpenAI: true, hasOpencodeGo: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.librarian?.fallback_models).toBeDefined() expect(result.agents?.librarian?.fallback_models?.length).toBeGreaterThan(0) }) - test("librarian omits fallback_models when only one provider matches", () => { - // #given only opencode-go is available - const config = createConfig({ hasOpencodeGo: true }) + test("librarian omits fallback_models when only ZAI is available", () => { + // #given only ZAI is available + const config = createConfig({ hasZaiCodingPlan: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should not have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("zai-coding-plan/glm-4.7") expect(result.agents?.librarian?.fallback_models).toBeUndefined() }) }) diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index 088c4515e..6378482c6 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -127,7 +127,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) { if (role === "librarian") { let agentConfig: AgentConfig | undefined - if (avail.opencodeGo) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.opencodeGo) { agentConfig = { model: "opencode-go/minimax-m2.7" } } else if (avail.zai) { agentConfig = { model: ZAI_MODEL } @@ -142,7 +144,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { if (role === "explore") { let agentConfig: AgentConfig - if (avail.native.claude) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.native.claude) { agentConfig = { model: "anthropic/claude-haiku-4-5" } } else if (avail.opencodeZen) { agentConfig = { model: "opencode/claude-haiku-4-5" } diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index da544156c..91e910f60 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -54,8 +54,10 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toMatchObject({ model: "opencode-go/minimax-m2.7" }) - expect(result.agents?.librarian).toMatchObject({ model: "opencode-go/minimax-m2.7" }) + expect(result.agents?.explore).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.librarian).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.explore).not.toMatchObject({ variant: "medium" }) + expect(result.agents?.librarian).not.toMatchObject({ variant: "medium" }) expect(result.categories?.quick).toMatchObject({ model: "openai/gpt-5.4-mini" }) }) })