diff --git a/src/cli/cli-installer.telemetry.test.ts b/src/cli/cli-installer.telemetry.test.ts index c4bdee652..c1b8eb8ac 100644 --- a/src/cli/cli-installer.telemetry.test.ts +++ b/src/cli/cli-installer.telemetry.test.ts @@ -22,6 +22,7 @@ describe("runCliInstaller telemetry isolation", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "isOpenCodeInstalled").mockResolvedValue(true), spyOn(configManager, "getOpenCodeVersion").mockResolvedValue("1.4.0"), diff --git a/src/cli/cli-installer.test.ts b/src/cli/cli-installer.test.ts index 38514fcf0..3fbb21f20 100644 --- a/src/cli/cli-installer.test.ts +++ b/src/cli/cli-installer.test.ts @@ -37,6 +37,7 @@ describe("runCliInstaller", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "isOpenCodeInstalled").mockResolvedValue(true), spyOn(configManager, "getOpenCodeVersion").mockResolvedValue("1.3.9"), @@ -83,6 +84,7 @@ describe("runCliInstaller", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "isOpenCodeInstalled").mockResolvedValue(true), spyOn(configManager, "getOpenCodeVersion").mockResolvedValue("1.4.0"), diff --git a/src/cli/cli-installer.ts b/src/cli/cli-installer.ts index 5db015531..72d5d8d7c 100644 --- a/src/cli/cli-installer.ts +++ b/src/cli/cli-installer.ts @@ -138,7 +138,8 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && - !config.hasOpencodeZen + !config.hasOpencodeZen && + !config.hasVercelAiGateway ) { printWarning("No model providers configured. Using opencode/big-pickle as fallback.") } diff --git a/src/cli/cli-program.ts b/src/cli/cli-program.ts index 15d3d0489..6d982e57b 100644 --- a/src/cli/cli-program.ts +++ b/src/cli/cli-program.ts @@ -33,6 +33,7 @@ program .option("--zai-coding-plan ", "Z.ai Coding Plan subscription: no, yes (default: no)") .option("--kimi-for-coding ", "Kimi For Coding subscription: no, yes (default: no)") .option("--opencode-go ", "OpenCode Go subscription: no, yes (default: no)") + .option("--vercel-ai-gateway ", "Vercel AI Gateway: no, yes (default: no)") .option("--skip-auth", "Skip authentication setup hints") .addHelpText("after", ` Examples: @@ -40,14 +41,15 @@ Examples: $ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no $ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes -Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi): +Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Vercel): Claude Native anthropic/ models (Opus, Sonnet, Haiku) OpenAI Native openai/ models (GPT-5.4 for Oracle) Gemini Native google/ models (Gemini 3.1 Pro, Flash) Copilot github-copilot/ models (fallback) OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.) - Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) + Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback) + Vercel vercel/ models (universal proxy, always last fallback) `) .action(async (options) => { const args: InstallArgs = { @@ -60,6 +62,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi): zaiCodingPlan: options.zaiCodingPlan, kimiForCoding: options.kimiForCoding, opencodeGo: options.opencodeGo, + vercelAiGateway: options.vercelAiGateway, skipAuth: options.skipAuth ?? false, } const exitCode = await install(args) diff --git a/src/cli/config-manager/generate-omo-config.test.ts b/src/cli/config-manager/generate-omo-config.test.ts index dbec67c00..50fe4e3d8 100644 --- a/src/cli/config-manager/generate-omo-config.test.ts +++ b/src/cli/config-manager/generate-omo-config.test.ts @@ -18,6 +18,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -42,6 +43,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -64,6 +66,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: true, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -71,7 +74,7 @@ describe("generateOmoConfig - model fallback system", () => { //#then expect((result.agents as Record).librarian.model).toBe("zai-coding-plan/glm-4.7") - expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4.6") }) test("uses native OpenAI models when only ChatGPT available", () => { @@ -86,6 +89,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -110,6 +114,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -126,7 +131,7 @@ describe("generateOmoConfig - model fallback system", () => { }> //#then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") expect(agents.sisyphus.fallback_models).toEqual([ { model: "openai/gpt-5.4", @@ -136,7 +141,7 @@ describe("generateOmoConfig - model fallback system", () => { expect(categories.deep.model).toBe("openai/gpt-5.4") expect(categories.deep.fallback_models).toEqual([ { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4.6", variant: "max", }, ]) @@ -154,6 +159,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when @@ -175,6 +181,7 @@ describe("generateOmoConfig - model fallback system", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } //#when diff --git a/src/cli/config-manager/write-omo-config.test.ts b/src/cli/config-manager/write-omo-config.test.ts index 10ccf7a27..7b7ba6409 100644 --- a/src/cli/config-manager/write-omo-config.test.ts +++ b/src/cli/config-manager/write-omo-config.test.ts @@ -20,6 +20,7 @@ const installConfig: InstallConfig = { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, } function getRecord(value: unknown): Record { diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index 217420c46..088c4515e 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -129,10 +129,10 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { let agentConfig: AgentConfig | undefined if (avail.opencodeGo) { agentConfig = { model: "opencode-go/minimax-m2.7" } - } else if (avail.vercelAiGateway) { - agentConfig = { model: "vercel/minimax/minimax-m2.7" } } else if (avail.zai) { agentConfig = { model: ZAI_MODEL } + } else if (avail.vercelAiGateway) { + agentConfig = { model: "vercel/minimax/minimax-m2.7" } } if (agentConfig) { agents[role] = attachAllFallbackModels(agentConfig, req.fallbackChain, avail) @@ -148,10 +148,10 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { agentConfig = { model: "opencode/claude-haiku-4-5" } } else if (avail.opencodeGo) { agentConfig = { model: "opencode-go/minimax-m2.7" } - } else if (avail.vercelAiGateway) { - agentConfig = { model: "vercel/minimax/minimax-m2.7-highspeed" } } else if (avail.copilot) { agentConfig = { model: "github-copilot/gpt-5-mini" } + } else if (avail.vercelAiGateway) { + agentConfig = { model: "vercel/minimax/minimax-m2.7-highspeed" } } else { agentConfig = { model: "opencode/gpt-5-nano" } } diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index 9d516dfdd..da544156c 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -14,6 +14,7 @@ function createConfig(overrides: Partial = {}): InstallConfig { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, ...overrides, } } diff --git a/src/cli/tui-installer.test.ts b/src/cli/tui-installer.test.ts index dc5ca718f..0e5b1344d 100644 --- a/src/cli/tui-installer.test.ts +++ b/src/cli/tui-installer.test.ts @@ -44,6 +44,7 @@ describe("runTuiInstaller", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "isOpenCodeInstalled").mockResolvedValue(true), spyOn(configManager, "getOpenCodeVersion").mockResolvedValue("1.3.9"), @@ -92,6 +93,7 @@ describe("runTuiInstaller", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "isOpenCodeInstalled").mockResolvedValue(true), spyOn(configManager, "getOpenCodeVersion").mockResolvedValue("1.4.0"), @@ -105,6 +107,7 @@ describe("runTuiInstaller", () => { hasZaiCodingPlan: false, hasKimiForCoding: false, hasOpencodeGo: false, + hasVercelAiGateway: false, }), spyOn(configManager, "addPluginToOpenCodeConfig").mockResolvedValue({ success: true, diff --git a/src/cli/tui-installer.ts b/src/cli/tui-installer.ts index 4272557c0..ef4b9088a 100644 --- a/src/cli/tui-installer.ts +++ b/src/cli/tui-installer.ts @@ -77,7 +77,7 @@ export async function runTuiInstaller(args: InstallArgs, version: string): Promi ) } - if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) { + if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen && !config.hasVercelAiGateway) { p.log.warn("No model providers configured. Using opencode/big-pickle as fallback.") }