fix(desktop): preserve local model provider endpoint

This commit is contained in:
atakan g 2026-07-16 01:49:40 +03:00 committed by Teknium
parent 237b0f5d5e
commit fa9217542d
3 changed files with 58 additions and 2 deletions

View file

@ -212,6 +212,53 @@ describe('ModelSettings', () => {
expect(screen.queryByRole('button', { name: 'Set up provider' })).toBeNull()
})
it('preserves a user-defined provider endpoint when applying the main model', async () => {
getGlobalModelOptions.mockResolvedValueOnce({
providers: [
{
name: 'Nous',
slug: 'nous',
models: ['hermes-4'],
authenticated: true
},
{
name: 'Ollama',
slug: 'local-ollama',
models: ['qwen3:latest'],
authenticated: true,
is_user_defined: true,
api_url: 'http://localhost:11434/v1'
}
]
})
setModelAssignment.mockResolvedValueOnce({
provider: 'local-ollama',
model: 'qwen3:latest',
gateway_tools: []
})
await renderModelSettings()
const providerSelect = (await screen.findAllByRole('combobox'))[0]
fireEvent.click(providerSelect)
fireEvent.click(await screen.findByRole('option', { name: 'Ollama' }))
const modelSelect = (await screen.findAllByRole('combobox'))[1]
fireEvent.click(modelSelect)
fireEvent.click(await screen.findByRole('option', { name: 'qwen3:latest' }))
fireEvent.click(await screen.findByRole('button', { name: 'Apply' }))
await waitFor(() =>
expect(setModelAssignment).toHaveBeenCalledWith({
model: 'qwen3:latest',
provider: 'local-ollama',
scope: 'main',
base_url: 'http://localhost:11434/v1'
})
)
})
it('writes the profile default speed (service_tier) when the fast switch is toggled', async () => {
await renderModelSettings()
await waitFor(() => expect(getHermesConfigRecord).toHaveBeenCalled())

View file

@ -619,7 +619,12 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
setError('')
try {
const result = await setModelAssignment({ model: selectedModel, provider: selectedProvider, scope: 'main' })
const result = await setModelAssignment({
model: selectedModel,
provider: selectedProvider,
scope: 'main',
...(selectedProviderRow?.api_url ? { base_url: selectedProviderRow.api_url } : {})
})
if (profileEpoch.current !== epoch) {
return
@ -636,7 +641,7 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
} finally {
setApplying(false)
}
}, [onMainModelChanged, refresh, selectedModel, selectedProvider])
}, [onMainModelChanged, refresh, selectedModel, selectedProvider, selectedProviderRow])
const setAuxiliaryToMain = useCallback(
async (task: string) => {

View file

@ -386,6 +386,10 @@ export interface ModelOptionProvider {
key_env?: string
/** True for providers defined via the user's `providers:` config block. */
is_user_defined?: boolean
/** OpenAI-compatible endpoint for a user-defined provider. The backend
* exposes this as `api_url`; model assignments send it back as `base_url`
* so switching providers does not discard the selected local endpoint. */
api_url?: string
/** Per-model pricing keyed by model id (present when the picker requested
* pricing and the provider supports live pricing). */
pricing?: Record<string, ModelPricing>