diff --git a/apps/server/tests/unit/providers/opencode-provider.test.ts b/apps/server/tests/unit/providers/opencode-provider.test.ts index aeecd83b..57e2fc38 100644 --- a/apps/server/tests/unit/providers/opencode-provider.test.ts +++ b/apps/server/tests/unit/providers/opencode-provider.test.ts @@ -109,7 +109,7 @@ describe('opencode-provider.ts', () => { const parseModelsOutput = ( provider as unknown as { parseModelsOutput: (output: string) => ModelDefinition[] } - ).parseModelsOutput; + ).parseModelsOutput.bind(provider); const models = parseModelsOutput(output); expect(models).toHaveLength(2); diff --git a/apps/ui/src/hooks/use-settings-sync.ts b/apps/ui/src/hooks/use-settings-sync.ts index a12daf92..41ef6693 100644 --- a/apps/ui/src/hooks/use-settings-sync.ts +++ b/apps/ui/src/hooks/use-settings-sync.ts @@ -19,7 +19,11 @@ import { useAppStore, type ThemeMode, THEME_STORAGE_KEY } from '@/store/app-stor import { useSetupStore } from '@/store/setup-store'; import { useAuthStore } from '@/store/auth-store'; import { waitForMigrationComplete, resetMigrationState } from './use-settings-migration'; -import type { GlobalSettings } from '@automaker/types'; +import { + DEFAULT_OPENCODE_MODEL, + getAllOpencodeModelIds, + type GlobalSettings, +} from '@automaker/types'; const logger = createLogger('SettingsSync'); @@ -424,6 +428,27 @@ export async function refreshSettingsFromServer(): Promise { const serverSettings = result.settings as unknown as GlobalSettings; const currentAppState = useAppStore.getState(); + const validOpencodeModelIds = new Set(getAllOpencodeModelIds()); + const incomingEnabledOpencodeModels = + serverSettings.enabledOpencodeModels ?? currentAppState.enabledOpencodeModels; + const sanitizedOpencodeDefaultModel = validOpencodeModelIds.has( + serverSettings.opencodeDefaultModel ?? currentAppState.opencodeDefaultModel + ) + ? (serverSettings.opencodeDefaultModel ?? currentAppState.opencodeDefaultModel) + : DEFAULT_OPENCODE_MODEL; + const sanitizedEnabledOpencodeModels = Array.from( + new Set(incomingEnabledOpencodeModels.filter((modelId) => validOpencodeModelIds.has(modelId))) + ); + + if (!sanitizedEnabledOpencodeModels.includes(sanitizedOpencodeDefaultModel)) { + sanitizedEnabledOpencodeModels.push(sanitizedOpencodeDefaultModel); + } + + const persistedDynamicModelIds = + serverSettings.enabledDynamicModelIds ?? currentAppState.enabledDynamicModelIds; + const sanitizedDynamicModelIds = persistedDynamicModelIds.filter( + (modelId) => !modelId.startsWith('amazon-bedrock/') + ); // Save theme to localStorage for fallback when server settings aren't available if (serverSettings.theme) { @@ -447,6 +472,9 @@ export async function refreshSettingsFromServer(): Promise { phaseModels: serverSettings.phaseModels, enabledCursorModels: serverSettings.enabledCursorModels, cursorDefaultModel: serverSettings.cursorDefaultModel, + enabledOpencodeModels: sanitizedEnabledOpencodeModels, + opencodeDefaultModel: sanitizedOpencodeDefaultModel, + enabledDynamicModelIds: sanitizedDynamicModelIds, autoLoadClaudeMd: serverSettings.autoLoadClaudeMd ?? false, keyboardShortcuts: { ...currentAppState.keyboardShortcuts,