diff --git a/src/main/kotlin/ee/carlrobert/codegpt/LegacyMigrationActivity.kt b/src/main/kotlin/ee/carlrobert/codegpt/LegacyMigrationActivity.kt new file mode 100644 index 00000000..efde197d --- /dev/null +++ b/src/main/kotlin/ee/carlrobert/codegpt/LegacyMigrationActivity.kt @@ -0,0 +1,36 @@ +package ee.carlrobert.codegpt + +import com.intellij.openapi.components.service +import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.ProjectActivity +import ee.carlrobert.codegpt.settings.GeneralSettings +import ee.carlrobert.codegpt.settings.migration.LegacySettingsMigration +import ee.carlrobert.codegpt.settings.models.ModelSettings + +class LegacyMigrationActivity : ProjectActivity { + + private val logger = thisLogger() + + override suspend fun execute(project: Project) { + try { + val generalState = GeneralSettings.getCurrentState() + val selectedService = generalState.selectedService + + if (selectedService == null) { + return + } + + val migratedState = LegacySettingsMigration.migrateIfNeeded() + if (migratedState != null) { + service().loadState(migratedState) + } + + generalState.selectedService = null + + } catch (exception: Exception) { + logger.error("Failed to execute legacy migration", exception) + GeneralSettings.getCurrentState().selectedService = null + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/migration/LegacySettingsMigration.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/migration/LegacySettingsMigration.kt index c78a28f5..b35452f8 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/migration/LegacySettingsMigration.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/migration/LegacySettingsMigration.kt @@ -21,36 +21,42 @@ object LegacySettingsMigration { private val logger = thisLogger() - fun migrateIfNeeded() { - try { - val selectedService = GeneralSettings.getCurrentState().selectedService + fun migrateIfNeeded(): ModelSettingsState? { + return try { + val generalState = GeneralSettings.getCurrentState() + val selectedService = generalState.selectedService + if (selectedService != null) { - val migratedState = createMigratedState(selectedService) - service().loadState(migratedState) + generalState.selectedService = null + createMigratedState(selectedService) + } else { + null } } catch (exception: Exception) { logger.error("Failed to migrate legacy settings", exception) + null } } private fun createMigratedState(selectedService: ServiceType): ModelSettingsState { - val state = ModelSettingsState() - val chatModel = getLegacyChatModelForService(selectedService) - state.setModelSelection(FeatureType.CHAT, chatModel, selectedService) - state.setModelSelection(FeatureType.AUTO_APPLY, chatModel, selectedService) - state.setModelSelection(FeatureType.COMMIT_MESSAGE, chatModel, selectedService) - state.setModelSelection(FeatureType.EDIT_CODE, chatModel, selectedService) - state.setModelSelection(FeatureType.LOOKUP, chatModel, selectedService) + return ModelSettingsState().apply { + val chatModel = getLegacyChatModelForService(selectedService) + + setModelSelection(FeatureType.CHAT, chatModel, selectedService) + setModelSelection(FeatureType.AUTO_APPLY, chatModel, selectedService) + setModelSelection(FeatureType.COMMIT_MESSAGE, chatModel, selectedService) + setModelSelection(FeatureType.EDIT_CODE, chatModel, selectedService) + setModelSelection(FeatureType.LOOKUP, chatModel, selectedService) - val codeModel = getLegacyCodeModelForService(selectedService) - state.setModelSelection(FeatureType.CODE_COMPLETION, codeModel, selectedService) - if (selectedService == ServiceType.PROXYAI) { - state.setModelSelection(FeatureType.NEXT_EDIT, ModelRegistry.ZETA, ServiceType.PROXYAI) - } else { - state.setModelSelection(FeatureType.NEXT_EDIT, null, selectedService) + val codeModel = getLegacyCodeModelForService(selectedService) + setModelSelection(FeatureType.CODE_COMPLETION, codeModel, selectedService) + + if (selectedService == ServiceType.PROXYAI) { + setModelSelection(FeatureType.NEXT_EDIT, ModelRegistry.ZETA, ServiceType.PROXYAI) + } else { + setModelSelection(FeatureType.NEXT_EDIT, null, selectedService) + } } - - return state } private fun getLegacyChatModelForService(serviceType: ServiceType): String { @@ -58,27 +64,25 @@ object LegacySettingsMigration { when (serviceType) { ServiceType.PROXYAI -> { val settings = service() - settings.state.chatCompletionSettings.model - ?: ModelRegistry.GEMINI_FLASH_2_5 + settings.state.chatCompletionSettings.model ?: ModelRegistry.GEMINI_FLASH_2_5 } ServiceType.OPENAI -> { - OpenAISettings.getCurrentState().model + OpenAISettings.getCurrentState().model ?: ModelRegistry.GPT_4_1 } ServiceType.ANTHROPIC -> { - AnthropicSettings.getCurrentState().model - ?: ModelRegistry.CLAUDE_SONNET_4_20250514 + AnthropicSettings.getCurrentState().model ?: ModelRegistry.CLAUDE_SONNET_4_20250514 } ServiceType.GOOGLE -> { - service().state.model - ?: GoogleModel.GEMINI_2_5_PRO.code + val settings = service() + settings.state.model ?: GoogleModel.GEMINI_2_5_PRO.code } ServiceType.OLLAMA -> { - service().state.model - ?: "llama3.2" + val settings = service() + settings.state.model ?: ModelRegistry.LLAMA_3_2 } ServiceType.LLAMA_CPP -> { @@ -91,17 +95,23 @@ object LegacySettingsMigration { } ServiceType.CUSTOM_OPENAI -> { - service().state.services - .map { it.chatCompletionSettings.body["model"] as String } - .lastOrNull() ?: "" + val customServicesSettings = service() + val services = customServicesSettings.state.services + + val activeServiceName = customServicesSettings.state.active.name + if (!activeServiceName.isNullOrBlank()) { + activeServiceName + } else { + services.map { it.name }.lastOrNull()?.takeIf { it.isNotBlank() } ?: "Default" + } } ServiceType.MISTRAL -> { - ModelRegistry.CODESTRAL_LATEST + ModelRegistry.DEVSTRAL_MEDIUM_2507 } } } catch (e: Exception) { - logger.warn("Could not get legacy model for service $serviceType, using default", e) + logger.warn("Failed to get legacy chat model for $serviceType", e) getDefaultModelForService(serviceType) } } @@ -140,7 +150,7 @@ object LegacySettingsMigration { ServiceType.CUSTOM_OPENAI -> { service().state.services - .map { it.codeCompletionSettings.body["model"] as String } + .map { it.name } .lastOrNull() ?: "" } @@ -149,8 +159,8 @@ object LegacySettingsMigration { } } } catch (e: Exception) { - logger.warn("Could not get legacy model for service $serviceType, using default", e) - getDefaultModelForService(serviceType) + logger.warn("Failed to get legacy code model for $serviceType", e) + null } } @@ -163,7 +173,18 @@ object LegacySettingsMigration { ServiceType.MISTRAL -> ModelRegistry.DEVSTRAL_MEDIUM_2507 ServiceType.OLLAMA -> ModelRegistry.LLAMA_3_2 ServiceType.LLAMA_CPP -> ModelRegistry.LLAMA_3_2_3B_INSTRUCT - ServiceType.CUSTOM_OPENAI -> ModelRegistry.GPT_4O + ServiceType.CUSTOM_OPENAI -> { + // For Custom OpenAI, try to use the active service name if available + // If not available, use a placeholder that won't break model selection + try { + val customServicesSettings = service() + val activeService = customServicesSettings.state.active + activeService?.name?.takeIf { it.isNotBlank() } ?: "Custom OpenAI" + } catch (e: Exception) { + logger.warn("Could not access CustomServicesSettings for default model, using placeholder", e) + "Custom OpenAI" + } + } } } } \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt index 43a600d8..914b779f 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt @@ -2,11 +2,11 @@ package ee.carlrobert.codegpt.settings.models import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.* +import com.intellij.openapi.diagnostic.thisLogger import ee.carlrobert.codegpt.settings.migration.LegacySettingsMigration import ee.carlrobert.codegpt.settings.service.FeatureType import ee.carlrobert.codegpt.settings.service.ModelChangeNotifier import ee.carlrobert.codegpt.settings.service.ServiceType -import ee.carlrobert.llm.client.codegpt.PricingPlan @Service @State( @@ -59,10 +59,8 @@ class ModelSettings : SimplePersistentStateComponent(ModelSe val oldState = this.state super.loadState(state) - LegacySettingsMigration.migrateIfNeeded() - migrateMissingProviderInformation() - notifyIfChanged(oldState, state) + notifyIfChanged(oldState, this.state) } fun setModel(featureType: FeatureType, model: String?, serviceType: ServiceType) { @@ -80,7 +78,6 @@ class ModelSettings : SimplePersistentStateComponent(ModelSe fun getModelSelection(featureType: FeatureType): ModelSelection { val details = getModelDetailsState(featureType) - if (details == null) { val defaultModel = ModelRegistry.getInstance().getDefaultModelForFeature(featureType) state.setModelSelection(featureType, defaultModel.model, defaultModel.provider) @@ -98,18 +95,16 @@ class ModelSettings : SimplePersistentStateComponent(ModelSe } } - fun getOrCreateModelSelection(featureType: FeatureType, ): ModelSelection { + fun getOrCreateModelSelection(featureType: FeatureType): ModelSelection { return getModelSelection(featureType) } fun getModelForFeature(featureType: FeatureType): String? { - val modelDetails = getModelDetailsState(featureType) - return modelDetails?.model + return getModelDetailsState(featureType)?.model } fun getProviderForFeature(featureType: FeatureType): ServiceType? { - val modelDetails = getModelDetailsState(featureType) - return modelDetails?.provider + return getModelDetailsState(featureType)?.provider } private fun notifyModelChange( diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsForm.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsForm.kt index 5d33d50a..fc1fe2fb 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsForm.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsForm.kt @@ -121,9 +121,12 @@ class ModelSettingsForm( state.getModelSelection(featureType) ?: ModelDetailsState() ) } + + val codeCompletionModelState = state.getModelSelection(FeatureType.CODE_COMPLETION) + val codeCompletionProvider = codeCompletionModelState?.provider ?: ServiceType.PROXYAI + updateNextEditButtonState(codeCompletionProvider) } - fun createPanel(): DialogPanel { return panel { FEATURE_GROUPS.forEach { featureGroup -> diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ModelSelectionService.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ModelSelectionService.kt index 4f7896d1..73e08171 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ModelSelectionService.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ModelSelectionService.kt @@ -17,7 +17,9 @@ class ModelSelectionService { pricingPlan: PricingPlan? = null ): ModelSelection { return try { - val modelDetailsState = service().state.getModelSelection(featureType) + val modelSettings = service() + val modelDetailsState = modelSettings.state.getModelSelection(featureType) + if (modelDetailsState != null && modelDetailsState.model != null && modelDetailsState.provider != null) { val foundModel = service().findModel(modelDetailsState.provider!!, modelDetailsState.model!!) if (foundModel != null) { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index aaea6915..e1957a8a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -25,6 +25,7 @@ +