feat: add sonnet 4.5 and codex models (proxyai)

This commit is contained in:
Carl-Robert Linnupuu 2025-10-15 13:58:00 +01:00
parent 86d5ed26e4
commit 58c7a320ee
9 changed files with 46 additions and 34 deletions

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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<ModelSettingsState>(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(

View file

@ -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),

View file

@ -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
)
}

View file

@ -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") }

View file

@ -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")
}
}

View file

@ -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)
}