diff --git a/apps/desktop/src/app/settings/fallback-models-field.test.tsx b/apps/desktop/src/app/settings/fallback-models-field.test.tsx
index 415ea4ba4..8abc71a65 100644
--- a/apps/desktop/src/app/settings/fallback-models-field.test.tsx
+++ b/apps/desktop/src/app/settings/fallback-models-field.test.tsx
@@ -43,6 +43,23 @@ async function renderField(value: unknown, onChange = vi.fn()) {
return onChange
}
+async function renderFieldWithRerender(value: unknown, onChange = vi.fn()) {
+ const { FallbackModelsField } = await import('./fallback-models-field')
+ const client = new QueryClient({ defaultOptions: { queries: { retry: false } } })
+ const view = render(
+
+
+
+ )
+
+ return (next: unknown) =>
+ view.rerender(
+
+
+
+ )
+}
+
const CHAIN = [
{ provider: 'copilot', model: 'gpt-5-mini' },
{ provider: 'openai-codex', model: 'gpt-5.4-mini' }
@@ -84,4 +101,13 @@ describe('FallbackModelsField', () => {
expect(screen.getByText(/No fallback models/)).toBeTruthy()
expect(screen.queryAllByLabelText('Remove')).toHaveLength(0)
})
+
+ it('resyncs rows when persisted config changes', async () => {
+ const rerender = await renderFieldWithRerender(CHAIN)
+ expect(screen.getAllByLabelText('Remove')).toHaveLength(2)
+
+ rerender([{ provider: 'nous', model: 'hermes-4' }])
+
+ await waitFor(() => expect(screen.getAllByLabelText('Remove')).toHaveLength(1))
+ })
})
diff --git a/apps/desktop/src/app/settings/fallback-models-field.tsx b/apps/desktop/src/app/settings/fallback-models-field.tsx
index b2b620115..d904d021f 100644
--- a/apps/desktop/src/app/settings/fallback-models-field.tsx
+++ b/apps/desktop/src/app/settings/fallback-models-field.tsx
@@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query'
-import { useState } from 'react'
+import { useEffect, useState } from 'react'
import { Button } from '@/components/ui/button'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
@@ -70,6 +70,12 @@ export function FallbackModelsField({
const [rows, setRows] = useState(() => normalizeEntries(value))
+ // Settings can reload after a profile/config change while this component
+ // stays mounted. Avoid displaying or saving the previous profile's chain.
+ useEffect(() => {
+ setRows(normalizeEntries(value))
+ }, [value])
+
const commit = (next: FallbackEntry[]) => {
setRows(next)
onChange(next.filter(entry => entry.provider && entry.model))