From 031a279b7f4f6e45f701f9b1bb143a759694f1be Mon Sep 17 00:00:00 2001 From: Carl-Robert Linnupuu Date: Wed, 15 Oct 2025 13:58:00 +0100 Subject: [PATCH] feat: add sonnet 4.5 and codex models (proxyai) --- gradle/libs.versions.toml | 2 +- .../codegpt/settings/models/ModelIcons.kt | 4 +-- .../codegpt/settings/models/ModelRegistry.kt | 36 +++++++++---------- .../codegpt/settings/models/ModelSettings.kt | 16 +++++++++ .../service/codegpt/CodeGPTAvailableModels.kt | 4 +-- .../codegpt/ui/textarea/UserInputPanel.kt | 4 +-- .../settings/models/ModelRegistryTest.kt | 6 ++-- .../models/ModelSelectionServiceTest.kt | 4 +-- .../settings/models/ModelSettingsTest.kt | 4 +-- 9 files changed, 46 insertions(+), 34 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0980b653..a056f3e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ jsoup = "1.21.2" jtokkit = "1.1.0" junit = "5.13.4" kotlin = "2.2.10" -llm-client = "0.8.53" +llm-client = "0.8.54" okio = "3.15.0" tree-sitter = "0.24.5" grpc = "1.73.0" diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelIcons.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelIcons.kt index 1511deae..e8f529d9 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelIcons.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelIcons.kt @@ -14,10 +14,10 @@ object ModelIcons { fun getProxyAIModelIcon(modelId: String): Icon? { return when (modelId) { - ModelRegistry.GPT_5, ModelRegistry.GPT_5_MINI, + ModelRegistry.GPT_5_CODEX, ModelRegistry.GPT_5, ModelRegistry.GPT_5_MINI, ModelRegistry.O4_MINI, ModelRegistry.GPT_4_1, ModelRegistry.GPT_4_1_MINI -> Icons.OpenAI - ModelRegistry.CLAUDE_4_SONNET_THINKING, ModelRegistry.CLAUDE_4_SONNET -> Icons.Anthropic + ModelRegistry.CLAUDE_4_5_SONNET_THINKING, ModelRegistry.CLAUDE_4_5_SONNET -> Icons.Anthropic ModelRegistry.GEMINI_PRO_2_5, ModelRegistry.GEMINI_FLASH_2_5 -> Icons.Google ModelRegistry.DEEPSEEK_R1, ModelRegistry.DEEPSEEK_V3 -> Icons.DeepSeek ModelRegistry.QWEN3_CODER -> Icons.Qwen diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistry.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistry.kt index 8452a30a..c79ee844 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistry.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistry.kt @@ -182,21 +182,21 @@ class ModelRegistry { PricingPlan.INDIVIDUAL to mapOf( FeatureType.CHAT to ModelSelection( ServiceType.PROXYAI, - CLAUDE_4_SONNET_THINKING, - "Claude 4 Sonnet Thinking" + CLAUDE_4_5_SONNET_THINKING, + "Claude 4.5 Sonnet Thinking" ), FeatureType.AUTO_APPLY to ModelSelection( ServiceType.PROXYAI, MERCURY_CODER, "Mercury Coder" ), - FeatureType.COMMIT_MESSAGE to ModelSelection(ServiceType.PROXYAI, GPT_5, "GPT-5"), + FeatureType.COMMIT_MESSAGE to ModelSelection(ServiceType.PROXYAI, GPT_5_CODEX, "GPT-5 Codex"), FeatureType.INLINE_EDIT to ModelSelection( ServiceType.PROXYAI, - CLAUDE_4_SONNET, + CLAUDE_4_5_SONNET, "Claude 4 Sonnet" ), - FeatureType.LOOKUP to ModelSelection(ServiceType.PROXYAI, GPT_5, "GPT-5"), + FeatureType.LOOKUP to ModelSelection(ServiceType.PROXYAI, GPT_5_CODEX, "GPT-5 Codex"), FeatureType.CODE_COMPLETION to ModelSelection( ServiceType.PROXYAI, MERCURY_CODER, @@ -365,8 +365,8 @@ class ModelRegistry { return listOf( ModelSelection( ServiceType.PROXYAI, - GPT_5, - "GPT-5", + GPT_5_CODEX, + "GPT-5 Codex", Icons.OpenAI, PricingPlan.INDIVIDUAL ), @@ -379,22 +379,15 @@ class ModelRegistry { ), ModelSelection( ServiceType.PROXYAI, - O4_MINI, - "o4-mini", - Icons.OpenAI, - PricingPlan.INDIVIDUAL - ), - ModelSelection( - ServiceType.PROXYAI, - CLAUDE_4_SONNET_THINKING, - "Claude Sonnet 4 (thinking)", + CLAUDE_4_5_SONNET_THINKING, + "Claude Sonnet 4.5 (thinking)", Icons.Anthropic, PricingPlan.INDIVIDUAL ), ModelSelection( ServiceType.PROXYAI, - CLAUDE_4_SONNET, - "Claude Sonnet 4", + CLAUDE_4_5_SONNET, + "Claude Sonnet 4.5", Icons.Anthropic, PricingPlan.INDIVIDUAL ), @@ -490,12 +483,12 @@ class ModelRegistry { GPT_4_1_NANO, O1_PREVIEW, O1_MINI, - GPT_5, GPT_5_MINI, GPT_4O, GPT_4_0125_PREVIEW, GPT_3_5_TURBO_INSTRUCT, - GPT_4_VISION_PREVIEW + GPT_4_VISION_PREVIEW, + GPT_5_CODEX, ) return openAIModels.mapNotNull { modelId -> @@ -620,6 +613,8 @@ class ModelRegistry { const val GEMINI_FLASH_2_5 = "gemini-flash-2.5" const val CLAUDE_4_SONNET = "claude-4-sonnet" const val CLAUDE_4_SONNET_THINKING = "claude-4-sonnet-thinking" + const val CLAUDE_4_5_SONNET = "claude-sonnet-4-5" + const val CLAUDE_4_5_SONNET_THINKING = "claude-sonnet-4-5-thinking" const val DEEPSEEK_R1 = "deepseek-r1" const val DEEPSEEK_V3 = "deepseek-v3" const val QWEN_2_5_32B_CODE = "qwen-2.5-32b-code" @@ -644,6 +639,7 @@ class ModelRegistry { const val GPT_4_VISION_PREVIEW = "gpt-4-vision-preview" const val GPT_5 = "gpt-5" const val GPT_5_MINI = "gpt-5-mini" + const val GPT_5_CODEX = "gpt-5-codex" // Anthropic Models const val CLAUDE_OPUS_4_20250514 = "claude-opus-4-20250514" 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 c7c3cf2b..4806bc80 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettings.kt @@ -7,6 +7,7 @@ import ee.carlrobert.codegpt.settings.service.ModelChangeNotifier import ee.carlrobert.codegpt.settings.service.ServiceType import ee.carlrobert.codegpt.settings.service.ServiceType.PROXYAI import ee.carlrobert.codegpt.settings.service.custom.CustomServicesSettings +import java.time.Month @Service @State( @@ -153,6 +154,21 @@ class ModelSettings : SimplePersistentStateComponent(ModelSe setModelWithProvider(it, ModelRegistry.MERCURY_CODER, PROXYAI) } } + listOf( + FeatureType.CHAT, + FeatureType.COMMIT_MESSAGE, + FeatureType.LOOKUP, + FeatureType.INLINE_EDIT + ).forEach { + val modelSelection = state.getModelSelection(it) + if (modelSelection?.provider == PROXYAI) { + if (modelSelection.model == ModelRegistry.CLAUDE_4_SONNET) { + setModelWithProvider(it, ModelRegistry.CLAUDE_4_5_SONNET, PROXYAI) + } else if (modelSelection.model == ModelRegistry.CLAUDE_4_SONNET_THINKING) { + setModelWithProvider(it, ModelRegistry.CLAUDE_4_5_SONNET_THINKING, PROXYAI) + } + } + } } private fun inferProviderFromModelCode( diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/codegpt/CodeGPTAvailableModels.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/codegpt/CodeGPTAvailableModels.kt index 342c9746..0c581ba8 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/codegpt/CodeGPTAvailableModels.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/codegpt/CodeGPTAvailableModels.kt @@ -14,8 +14,8 @@ object CodeGPTAvailableModels { CodeGPTModel("o4-mini", "o4-mini", Icons.OpenAI, INDIVIDUAL), CodeGPTModel("GPT-5", "gpt-5", Icons.OpenAI, INDIVIDUAL), CodeGPTModel("GPT-5 Mini", "gpt-5-mini", Icons.OpenAI, ANONYMOUS), - CodeGPTModel("Claude Sonnet 4 (thinking)", "claude-4-sonnet-thinking", Icons.Anthropic, INDIVIDUAL), - CodeGPTModel("Claude Sonnet 4", "claude-4-sonnet", Icons.Anthropic, INDIVIDUAL), + CodeGPTModel("Claude Sonnet 4.5 (thinking)", "claude-sonnet-4-5-thinking", Icons.Anthropic, INDIVIDUAL), + CodeGPTModel("Claude Sonnet 4.5", "claude-sonnet-4-5", Icons.Anthropic, INDIVIDUAL), CodeGPTModel("Gemini 2.5 Pro", "gemini-pro-2.5", Icons.Google, INDIVIDUAL), CodeGPTModel("Gemini 2.5 Flash", "gemini-flash-2.5", Icons.Google, ANONYMOUS), CodeGPTModel("DeepSeek R1", "deepseek-r1", Icons.DeepSeek, INDIVIDUAL), diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/UserInputPanel.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/UserInputPanel.kt index 7b4caa20..a899b162 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/UserInputPanel.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/UserInputPanel.kt @@ -544,8 +544,8 @@ class UserInputPanel @JvmOverloads constructor( ModelRegistry.GPT_4_1_MINI, ModelRegistry.GEMINI_PRO_2_5, ModelRegistry.GEMINI_FLASH_2_5, - ModelRegistry.CLAUDE_4_SONNET, - ModelRegistry.CLAUDE_4_SONNET_THINKING + ModelRegistry.CLAUDE_4_5_SONNET, + ModelRegistry.CLAUDE_4_5_SONNET_THINKING ) } diff --git a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistryTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistryTest.kt index 65f47e87..6680045c 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistryTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelRegistryTest.kt @@ -19,8 +19,8 @@ class ModelRegistryTest : IntegrationTest() { val result = modelRegistry.getDefaultModelForFeature(FeatureType.CHAT, PricingPlan.INDIVIDUAL) assertThat(result.provider).isEqualTo(ServiceType.PROXYAI) - assertThat(result.model).isEqualTo("claude-4-sonnet-thinking") - assertThat(result.displayName).isEqualTo("Claude 4 Sonnet Thinking") + assertThat(result.model).isEqualTo("claude-sonnet-4-5-thinking") + assertThat(result.displayName).isEqualTo("Claude 4.5 Sonnet Thinking") } fun `test getDefaultModelForFeature with free plan returns free model`() { @@ -66,7 +66,7 @@ class ModelRegistryTest : IntegrationTest() { fun `test getAllModelsForFeature with chat returns chat models only`() { val result = modelRegistry.getAllModelsForFeature(FeatureType.CHAT) - assertThat(result).anyMatch { it.provider == ServiceType.PROXYAI && it.model == "claude-4-sonnet-thinking" } + assertThat(result).anyMatch { it.provider == ServiceType.PROXYAI && it.model == "claude-sonnet-4-5-thinking" } assertThat(result).anyMatch { it.provider == ServiceType.OPENAI && it.model == "gpt-4.1" } assertThat(result).anyMatch { it.provider == ServiceType.ANTHROPIC && it.model == "claude-sonnet-4-20250514" } assertThat(result).anyMatch { it.provider == ServiceType.GOOGLE && it.model.contains("gemini") } diff --git a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSelectionServiceTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSelectionServiceTest.kt index 169d436b..08b145ee 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSelectionServiceTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSelectionServiceTest.kt @@ -40,7 +40,7 @@ class ModelSelectionServiceTest : IntegrationTest() { val freeResult = modelSelectionService.getModelSelectionForFeature(FeatureType.CHAT, PricingPlan.FREE) - assertThat(individualResult.model).isEqualTo("claude-4-sonnet-thinking") + assertThat(individualResult.model).isEqualTo("claude-sonnet-4-5-thinking") assertThat(freeResult.model).isEqualTo("qwen3-coder") } @@ -75,6 +75,6 @@ class ModelSelectionServiceTest : IntegrationTest() { val result = modelSelectionService.getModelForFeature(FeatureType.CHAT, PricingPlan.INDIVIDUAL) - assertThat(result).isEqualTo("claude-4-sonnet-thinking") + assertThat(result).isEqualTo("claude-sonnet-4-5-thinking") } } \ No newline at end of file diff --git a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsTest.kt index d1131e5f..c29ef22e 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/settings/models/ModelSettingsTest.kt @@ -120,11 +120,11 @@ class ModelSettingsTest : IntegrationTest() { fun `test setModelWithProvider with edit code triggers edit code notification`() { lastNotification.set(null) - modelSettings.setModelWithProvider(FeatureType.INLINE_EDIT, "claude-4-sonnet", ServiceType.PROXYAI) + modelSettings.setModelWithProvider(FeatureType.INLINE_EDIT, "claude-4-5-sonnet", ServiceType.PROXYAI) val notification = lastNotification.get() assertThat(notification!!.featureType).isEqualTo(FeatureType.INLINE_EDIT) - assertThat(notification.model).isEqualTo("claude-4-sonnet") + assertThat(notification.model).isEqualTo("claude-4-5-sonnet") assertThat(notification.serviceType).isEqualTo(ServiceType.PROXYAI) }