mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-30 16:23:35 +08:00
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:
parent
0a7db60394
commit
65e662450c
@ -97,11 +97,12 @@ describe('ModelSelector', () => {
|
|||||||
|
|
||||||
render(<ModelSelector runtimeKey="session-oauth-on-open" />)
|
render(<ModelSelector runtimeKey="session-oauth-on-open" />)
|
||||||
|
|
||||||
await clickByRole(/alpha/i)
|
await clickByRole(/provider-main/i)
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
fireEvent.keyDown(document, { key: 'Escape' })
|
||||||
await Promise.resolve()
|
await Promise.resolve()
|
||||||
})
|
})
|
||||||
await clickByRole(/alpha/i)
|
await clickByRole(/provider-main/i)
|
||||||
|
|
||||||
expect(fetchClaudeStatus).toHaveBeenCalledTimes(1)
|
expect(fetchClaudeStatus).toHaveBeenCalledTimes(1)
|
||||||
expect(fetchOpenAIStatus).toHaveBeenCalledTimes(1)
|
expect(fetchOpenAIStatus).toHaveBeenCalledTimes(1)
|
||||||
@ -192,7 +193,7 @@ describe('ModelSelector', () => {
|
|||||||
|
|
||||||
render(<ModelSelector runtimeKey="session-1" />)
|
render(<ModelSelector runtimeKey="session-1" />)
|
||||||
|
|
||||||
await clickByRole(/alpha/i)
|
await clickByRole(/provider-main/i)
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(screen.getByRole('button', { name: /provider-fast/ }))
|
fireEvent.click(screen.getByRole('button', { name: /provider-fast/ }))
|
||||||
await Promise.resolve()
|
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 () => {
|
it('keeps runtime effort scoped to the selected session', async () => {
|
||||||
const setSessionRuntime = vi.fn()
|
const setSessionRuntime = vi.fn()
|
||||||
useSettingsStore.setState({
|
useSettingsStore.setState({
|
||||||
@ -249,12 +295,12 @@ describe('ModelSelector', () => {
|
|||||||
|
|
||||||
render(<ModelSelector runtimeKey="session-1" />)
|
render(<ModelSelector runtimeKey="session-1" />)
|
||||||
|
|
||||||
await clickByRole(/alpha/i)
|
await clickByRole(/provider-main/i)
|
||||||
await clickByRole(/^High$/)
|
await clickByRole(/^High$/)
|
||||||
|
|
||||||
expect(useSessionRuntimeStore.getState().selections['session-1']).toEqual({
|
expect(useSessionRuntimeStore.getState().selections['session-1']).toEqual({
|
||||||
providerId: 'provider-a',
|
providerId: 'provider-a',
|
||||||
modelId: 'alpha',
|
modelId: 'provider-main',
|
||||||
effortLevel: 'high',
|
effortLevel: 'high',
|
||||||
})
|
})
|
||||||
expect(useSessionRuntimeStore.getState().selections['session-2']).toEqual({
|
expect(useSessionRuntimeStore.getState().selections['session-2']).toEqual({
|
||||||
@ -264,7 +310,7 @@ describe('ModelSelector', () => {
|
|||||||
})
|
})
|
||||||
expect(setSessionRuntime).toHaveBeenCalledWith('session-1', {
|
expect(setSessionRuntime).toHaveBeenCalledWith('session-1', {
|
||||||
providerId: 'provider-a',
|
providerId: 'provider-a',
|
||||||
modelId: 'alpha',
|
modelId: 'provider-main',
|
||||||
effortLevel: 'high',
|
effortLevel: 'high',
|
||||||
})
|
})
|
||||||
expect(useSettingsStore.getState().effortLevel).toBe('max')
|
expect(useSettingsStore.getState().effortLevel).toBe('max')
|
||||||
@ -357,7 +403,7 @@ describe('ModelSelector', () => {
|
|||||||
|
|
||||||
render(<ModelSelector runtimeKey="session-hide" />)
|
render(<ModelSelector runtimeKey="session-hide" />)
|
||||||
|
|
||||||
await clickByRole(/alpha/i)
|
await clickByRole(/provider-main/i)
|
||||||
|
|
||||||
const dropdown = screen.getByTestId('model-selector-dropdown')
|
const dropdown = screen.getByTestId('model-selector-dropdown')
|
||||||
expect(dropdown.textContent).not.toContain('Claude Official')
|
expect(dropdown.textContent).not.toContain('Claude Official')
|
||||||
|
|||||||
@ -146,15 +146,17 @@ function resolveDefaultRuntimeSelection(
|
|||||||
providers: SavedProvider[],
|
providers: SavedProvider[],
|
||||||
currentModelId: string | undefined,
|
currentModelId: string | undefined,
|
||||||
): RuntimeSelection {
|
): RuntimeSelection {
|
||||||
const inferredProviderId = activeId ?? (
|
const activeProvider = activeId
|
||||||
activeProviderName
|
? providers.find((provider) => provider.id === activeId)
|
||||||
? providers.find((provider) => provider.name === activeProviderName)?.id ?? null
|
: activeProviderName
|
||||||
: null
|
? providers.find((provider) => provider.name === activeProviderName)
|
||||||
)
|
: undefined
|
||||||
|
const inferredProviderId = activeId ?? activeProvider?.id ?? null
|
||||||
|
const providerMainModelId = activeProvider?.models.main.trim()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
providerId: inferredProviderId,
|
providerId: inferredProviderId,
|
||||||
modelId: currentModelId ?? (
|
modelId: providerMainModelId || currentModelId || (
|
||||||
inferredProviderId === OPENAI_OFFICIAL_PROVIDER_ID
|
inferredProviderId === OPENAI_OFFICIAL_PROVIDER_ID
|
||||||
? OPENAI_OFFICIAL_DEFAULT_MODEL_ID
|
? OPENAI_OFFICIAL_DEFAULT_MODEL_ID
|
||||||
: OFFICIAL_DEFAULT_MODEL_ID
|
: OFFICIAL_DEFAULT_MODEL_ID
|
||||||
|
|||||||
@ -115,6 +115,7 @@ describe('providerStore runtime refresh', () => {
|
|||||||
providerId: provider.id,
|
providerId: provider.id,
|
||||||
modelId: 'model-main',
|
modelId: 'model-main',
|
||||||
})
|
})
|
||||||
|
expect(settingsSetModelMock).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('keeps an explicit provider model selection when the model still exists', async () => {
|
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(settingsSetModelMock).toHaveBeenCalledWith('model-main')
|
||||||
expect(settingsFetchAllMock).toHaveBeenCalled()
|
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', () => {
|
describe('providerStore reorderProviders', () => {
|
||||||
|
|||||||
@ -203,7 +203,16 @@ export const useProviderStore = create<ProviderStore>((set, get) => ({
|
|||||||
updateProvider: async (id, input) => {
|
updateProvider: async (id, input) => {
|
||||||
const { provider } = await providersApi.update(id, input)
|
const { provider } = await providersApi.update(id, input)
|
||||||
await get().fetchProviders()
|
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
|
return provider
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user