From 12748f511e8ee31731b2accbbf4f361b13482da9 Mon Sep 17 00:00:00 2001 From: Junyong Park Date: Sun, 13 Sep 2026 13:31:52 +0900 Subject: [PATCH] fix(openai-native): use canonical default model Use openAiNativeDefaultModelId for the shared OpenAI Native fallback. Cover default selection while router models load and preserve explicitly configured models with focused regression tests. Fixes #992 Signed-off-by: JunyongParkDev --- .../__tests__/provider-default-model.test.ts | 5 +++ packages/types/src/providers/index.ts | 4 +-- .../hooks/__tests__/useSelectedModel.spec.ts | 31 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/types/src/__tests__/provider-default-model.test.ts b/packages/types/src/__tests__/provider-default-model.test.ts index 33ba019253..9957603dda 100644 --- a/packages/types/src/__tests__/provider-default-model.test.ts +++ b/packages/types/src/__tests__/provider-default-model.test.ts @@ -19,6 +19,7 @@ import { internationalZAiDefaultModelId, kimiCodeDefaultModelId, mainlandZAiDefaultModelId, + openAiNativeDefaultModelId, openRouterDefaultModelId, vscodeLlmDefaultModelId, zooGatewayDefaultModelId, @@ -33,6 +34,10 @@ describe("getProviderDefaultModelId", () => { expect(getProviderDefaultModelId(providerIdentifiers.vscodeLm)).toBe(vscodeLlmDefaultModelId) }) + it("uses the canonical OpenAI Native default model", () => { + expect(getProviderDefaultModelId(providerIdentifiers.openaiNative)).toBe(openAiNativeDefaultModelId) + }) + it.each([ [providerIdentifiers.kimiCode, kimiCodeDefaultModelId], [providerIdentifiers.zooGateway, zooGatewayDefaultModelId], diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index b26476eaed..ed0c583912 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -42,6 +42,7 @@ import { geminiDefaultModelId } from "./gemini.js" import { litellmDefaultModelId } from "./lite-llm.js" import { mistralDefaultModelId } from "./mistral.js" import { moonshotDefaultModelId } from "./moonshot.js" +import { openAiNativeDefaultModelId } from "./openai.js" import { openAiCodexDefaultModelId } from "./openai-codex.js" import { openRouterDefaultModelId } from "./openrouter.js" import { poeDefaultModelId } from "./poe.js" @@ -105,8 +106,7 @@ export function getProviderDefaultModelId( case providerIdentifiers.zai: return options?.isChina ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId case providerIdentifiers.openaiNative: - // TODO(#992): Replace this stale fallback with openAiNativeDefaultModelId. - return "gpt-4o" // Based on openai-native patterns + return openAiNativeDefaultModelId case providerIdentifiers.openaiCodex: return openAiCodexDefaultModelId case providerIdentifiers.mistral: diff --git a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts index d5ef35672b..64d3067092 100644 --- a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts +++ b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts @@ -18,6 +18,8 @@ import { nanoGptDefaultModelId, nanoGptDefaultModelInfo, openAiModelInfoSaneDefaults, + openAiNativeDefaultModelId, + openAiNativeModels, minimaxDefaultModelId, minimaxModels, friendliDefaultModelId, @@ -109,6 +111,35 @@ describe("useSelectedModel", () => { ] as const const configuredModelInfo: ModelInfo = { contextWindow: 1, supportsPromptCache: false } + describe("OpenAI Native model selection", () => { + beforeEach(() => { + mockUseRouterModels.mockReturnValue(createRouterModelsResult({})) + mockUseOpenRouterModelProviders.mockReturnValue(createOpenRouterModelProvidersResult({})) + }) + + it.each([false, true])("uses the canonical default with router loading=%s", (isLoading) => { + mockUseRouterModels.mockReturnValue(createRouterModelsResult(isLoading ? undefined : {}, { isLoading })) + + const { result } = renderHook(() => useSelectedModel({ apiProvider: providerIdentifiers.openaiNative }), { + wrapper: createWrapper(), + }) + + expect(result.current.id).toBe(openAiNativeDefaultModelId) + expect(result.current.info).toEqual(openAiNativeModels[openAiNativeDefaultModelId]) + expect(result.current.isLoading).toBe(false) + }) + + it("preserves an explicitly configured model even when it is the former fallback", () => { + const { result } = renderHook( + () => useSelectedModel({ apiProvider: providerIdentifiers.openaiNative, apiModelId: "gpt-4o" }), + { wrapper: createWrapper() }, + ) + + expect(result.current.id).toBe("gpt-4o") + expect(result.current.info).toEqual(openAiNativeModels["gpt-4o"]) + }) + }) + it.each(dynamicProviderCases)("uses router data for %s", (provider, modelIdKey) => { const modelInfo: ModelInfo = { contextWindow: 42_000, supportsPromptCache: false } mockUseRouterModels.mockReturnValue(createRouterModelsResult({ [provider]: { model: modelInfo } }))