fix(desktop): default new sessions to provider main model (#818)

Tested: bun run check:desktop
Confidence: high
Scope-risk: narrow
This commit is contained in:
程序员阿江(Relakkes) 2026-06-15 23:00:20 +08:00
parent 0a7db60394
commit 65e662450c
4 changed files with 87 additions and 14 deletions

View File

@ -97,11 +97,12 @@ describe('ModelSelector', () => {
render(<ModelSelector runtimeKey="session-oauth-on-open" />)
await clickByRole(/alpha/i)
await clickByRole(/provider-main/i)
await act(async () => {
fireEvent.keyDown(document, { key: 'Escape' })
await Promise.resolve()
})
await clickByRole(/alpha/i)
await clickByRole(/provider-main/i)
expect(fetchClaudeStatus).toHaveBeenCalledTimes(1)
expect(fetchOpenAIStatus).toHaveBeenCalledTimes(1)
@ -192,7 +193,7 @@ describe('ModelSelector', () => {
render(<ModelSelector runtimeKey="session-1" />)
await clickByRole(/alpha/i)
await clickByRole(/provider-main/i)
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: /provider-fast/ }))
await Promise.resolve()
@ -210,6 +211,51 @@ describe('ModelSelector', () => {
})
})
it('defaults blank provider-scoped runtime selections to the active provider main model', async () => {
useSettingsStore.setState({
locale: 'en',
availableModels: [
{ id: 'deepseek-v4-flash', name: 'deepseek-v4-flash', description: 'Main Model · Haiku Model', context: '' },
{ id: 'deepseek-v4-pro', name: 'deepseek-v4-pro', description: 'Sonnet Model · Opus Model', context: '' },
],
currentModel: { id: 'deepseek-v4-pro', name: 'deepseek-v4-pro', description: 'Sonnet Model · Opus Model', context: '' },
activeProviderName: 'Custom-DeepSeek-OpenAI',
})
useProviderStore.setState({
providers: [{
id: 'deepseek-provider',
presetId: 'custom',
name: 'Custom-DeepSeek-OpenAI',
apiKey: '***',
baseUrl: 'https://api.deepseek.com',
apiFormat: 'openai_chat',
models: {
main: 'deepseek-v4-flash',
haiku: 'deepseek-v4-flash',
sonnet: 'deepseek-v4-pro',
opus: 'deepseek-v4-pro',
},
}],
activeId: 'deepseek-provider',
hasLoadedProviders: true,
isLoading: true,
})
render(<ModelSelector runtimeKey="blank-session" />)
const trigger = screen.getByRole('button', { name: /deepseek-v4-flash/i })
await act(async () => {
fireEvent.click(trigger)
await Promise.resolve()
})
const flashOption = screen
.getAllByRole('button', { name: /deepseek-v4-flash/i })
.find((button) => button.textContent?.includes('Main Model'))
expect(flashOption).toBeDefined()
expect(flashOption?.className).toContain('border-[var(--color-model-option-selected-border)]')
})
it('keeps runtime effort scoped to the selected session', async () => {
const setSessionRuntime = vi.fn()
useSettingsStore.setState({
@ -249,12 +295,12 @@ describe('ModelSelector', () => {
render(<ModelSelector runtimeKey="session-1" />)
await clickByRole(/alpha/i)
await clickByRole(/provider-main/i)
await clickByRole(/^High$/)
expect(useSessionRuntimeStore.getState().selections['session-1']).toEqual({
providerId: 'provider-a',
modelId: 'alpha',
modelId: 'provider-main',
effortLevel: 'high',
})
expect(useSessionRuntimeStore.getState().selections['session-2']).toEqual({
@ -264,7 +310,7 @@ describe('ModelSelector', () => {
})
expect(setSessionRuntime).toHaveBeenCalledWith('session-1', {
providerId: 'provider-a',
modelId: 'alpha',
modelId: 'provider-main',
effortLevel: 'high',
})
expect(useSettingsStore.getState().effortLevel).toBe('max')
@ -357,7 +403,7 @@ describe('ModelSelector', () => {
render(<ModelSelector runtimeKey="session-hide" />)
await clickByRole(/alpha/i)
await clickByRole(/provider-main/i)
const dropdown = screen.getByTestId('model-selector-dropdown')
expect(dropdown.textContent).not.toContain('Claude Official')

View File

@ -146,15 +146,17 @@ function resolveDefaultRuntimeSelection(
providers: SavedProvider[],
currentModelId: string | undefined,
): RuntimeSelection {
const inferredProviderId = activeId ?? (
activeProviderName
? providers.find((provider) => provider.name === activeProviderName)?.id ?? null
: null
)
const activeProvider = activeId
? providers.find((provider) => provider.id === activeId)
: activeProviderName
? providers.find((provider) => provider.name === activeProviderName)
: undefined
const inferredProviderId = activeId ?? activeProvider?.id ?? null
const providerMainModelId = activeProvider?.models.main.trim()
return {
providerId: inferredProviderId,
modelId: currentModelId ?? (
modelId: providerMainModelId || currentModelId || (
inferredProviderId === OPENAI_OFFICIAL_PROVIDER_ID
? OPENAI_OFFICIAL_DEFAULT_MODEL_ID
: OFFICIAL_DEFAULT_MODEL_ID

View File

@ -115,6 +115,7 @@ describe('providerStore runtime refresh', () => {
providerId: provider.id,
modelId: 'model-main',
})
expect(settingsSetModelMock).not.toHaveBeenCalled()
})
it('keeps an explicit provider model selection when the model still exists', async () => {
@ -181,6 +182,21 @@ describe('providerStore runtime refresh', () => {
expect(settingsSetModelMock).toHaveBeenCalledWith('model-main')
expect(settingsFetchAllMock).toHaveBeenCalled()
})
it('sets the provider main model when updating the active saved provider', async () => {
const provider = makeProvider({ models: { main: 'model-flash', haiku: 'model-flash', sonnet: 'model-pro', opus: 'model-pro' } })
providersApiMock.update.mockResolvedValue({ provider })
providersApiMock.list.mockResolvedValue({
providers: [provider],
activeId: provider.id,
})
const { useProviderStore } = await import('./providerStore')
await useProviderStore.getState().updateProvider(provider.id, { models: provider.models })
expect(settingsSetModelMock).toHaveBeenCalledWith('model-flash')
expect(settingsFetchAllMock).toHaveBeenCalled()
})
})
describe('providerStore reorderProviders', () => {

View File

@ -203,7 +203,16 @@ export const useProviderStore = create<ProviderStore>((set, get) => ({
updateProvider: async (id, input) => {
const { provider } = await providersApi.update(id, input)
await get().fetchProviders()
refreshConnectedSessionsForProvider(provider, get().activeId)
const activeId = get().activeId
if (activeId === provider.id && input.models !== undefined) {
const mainModelId = provider.models.main.trim()
if (mainModelId) {
const settings = useSettingsStore.getState()
await settings.setModel(mainModelId)
await settings.fetchAll()
}
}
refreshConnectedSessionsForProvider(provider, activeId)
return provider
},