Skip to content

Commit 08f013c

Browse files
authored
Merge pull request #506 from phodal/feat/add-new-model-config-support
feat: Add support for creating new model configs in ModelConfigDialog
2 parents f949a61 + 18e7818 commit 08f013c

File tree

17 files changed

+730
-13
lines changed

17 files changed

+730
-13
lines changed

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fun IdeaBottomToolbar(
3939
currentConfigName: String? = null,
4040
onConfigSelect: (NamedModelConfig) -> Unit = {},
4141
onConfigureClick: () -> Unit = {},
42+
onAddNewConfig: () -> Unit = {},
4243
modifier: Modifier = Modifier
4344
) {
4445
Row(
@@ -59,7 +60,8 @@ fun IdeaBottomToolbar(
5960
availableConfigs = availableConfigs,
6061
currentConfigName = currentConfigName,
6162
onConfigSelect = onConfigSelect,
62-
onConfigureClick = onConfigureClick
63+
onConfigureClick = onConfigureClick,
64+
onAddNewConfig = onAddNewConfig
6365
)
6466

6567
// Token usage indicator (subtle)

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fun IdeaModelSelector(
3535
currentConfigName: String?,
3636
onConfigSelect: (NamedModelConfig) -> Unit,
3737
onConfigureClick: () -> Unit,
38+
onAddNewConfig: () -> Unit,
3839
modifier: Modifier = Modifier
3940
) {
4041
var expanded by remember { mutableStateOf(false) }
@@ -131,7 +132,32 @@ fun IdeaModelSelector(
131132
separator()
132133
}
133134

134-
// Configure button
135+
// Add New Config button
136+
selectableItem(
137+
selected = false,
138+
onClick = {
139+
onAddNewConfig()
140+
expanded = false
141+
}
142+
) {
143+
Row(
144+
horizontalArrangement = Arrangement.spacedBy(8.dp),
145+
verticalAlignment = Alignment.CenterVertically
146+
) {
147+
Icon(
148+
imageVector = IdeaComposeIcons.Add,
149+
contentDescription = null,
150+
tint = JewelTheme.globalColors.text.normal,
151+
modifier = Modifier.size(16.dp)
152+
)
153+
Text(
154+
text = "Add New Config",
155+
style = JewelTheme.defaultTextStyle.copy(fontSize = 13.sp)
156+
)
157+
}
158+
}
159+
160+
// Configure button (edit current config)
135161
selectableItem(
136162
selected = false,
137163
onClick = {

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/SwingBottomToolbar.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class SwingBottomToolbar(
3232
private var availableConfigs: List<NamedModelConfig> = emptyList()
3333
private var onConfigSelect: (NamedModelConfig) -> Unit = {}
3434
private var onConfigureClick: () -> Unit = {}
35+
private var onAddNewConfig: () -> Unit = {}
3536
private var isProcessing = false
3637
private var isEnhancing = false
3738

@@ -52,6 +53,16 @@ class SwingBottomToolbar(
5253
}
5354
add(modelComboBox)
5455

56+
// Add New Config button
57+
val addConfigButton = JButton(AllIcons.General.Add).apply {
58+
toolTipText = "Add New Config"
59+
preferredSize = Dimension(28, 28)
60+
isBorderPainted = false
61+
isContentAreaFilled = false
62+
addActionListener { onAddNewConfig() }
63+
}
64+
add(addConfigButton)
65+
5566
tokenLabel.foreground = JBUI.CurrentTheme.Label.disabledForeground()
5667
add(tokenLabel)
5768
}
@@ -138,5 +149,9 @@ class SwingBottomToolbar(
138149
fun setOnConfigureClick(callback: () -> Unit) {
139150
onConfigureClick = callback
140151
}
152+
153+
fun setOnAddNewConfig(callback: () -> Unit) {
154+
onAddNewConfig = callback
155+
}
141156
}
142157

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ fun IdeaAgentApp(
6565
var isExecuting by remember { mutableStateOf(false) }
6666
var currentPlan by remember { mutableStateOf<AgentPlan?>(null) }
6767
var showConfigDialog by remember { mutableStateOf(false) }
68+
var isNewConfig by remember { mutableStateOf(false) }
6869
var mcpPreloadingMessage by remember { mutableStateOf("") }
6970
var configWrapper by remember { mutableStateOf<AutoDevConfigWrapper?>(null) }
7071
var currentModelConfig by remember { mutableStateOf<ModelConfig?>(null) }
@@ -89,6 +90,9 @@ fun IdeaAgentApp(
8990
IdeaLaunchedEffect(viewModel, project = project) {
9091
viewModel.showConfigDialog.collect { showConfigDialog = it }
9192
}
93+
IdeaLaunchedEffect(viewModel, project = project) {
94+
viewModel.isNewConfig.collect { isNewConfig = it }
95+
}
9296
IdeaLaunchedEffect(viewModel, project = project) {
9397
viewModel.mcpPreloadingMessage.collect { mcpPreloadingMessage = it }
9498
}
@@ -217,7 +221,8 @@ fun IdeaAgentApp(
217221
viewModel.setActiveConfig(config.name)
218222
},
219223
currentPlan = currentPlan,
220-
onConfigureClick = { viewModel.setShowConfigDialog(true) }
224+
onConfigureClick = { viewModel.showEditConfigDialog() },
225+
onAddNewConfig = { viewModel.showAddNewConfigDialog() }
221226
)
222227
}
223228
)
@@ -266,7 +271,8 @@ fun IdeaAgentApp(
266271
onConfigSelect = { config ->
267272
viewModel.setActiveConfig(config.name)
268273
},
269-
onConfigureClick = { viewModel.setShowConfigDialog(true) }
274+
onConfigureClick = { viewModel.showEditConfigDialog() },
275+
onAddNewConfig = { viewModel.showAddNewConfigDialog() }
270276
)
271277
}
272278
)
@@ -304,12 +310,13 @@ fun IdeaAgentApp(
304310
// DialogWrapper must be created on EDT, so we use invokeLater
305311
DisposableEffect(showConfigDialog) {
306312
if (showConfigDialog) {
307-
val dialogConfig = currentModelConfig ?: ModelConfig()
313+
val dialogConfig = if (isNewConfig) ModelConfig() else (currentModelConfig ?: ModelConfig())
314+
val dialogConfigName = if (isNewConfig) null else currentConfigName
308315
com.intellij.openapi.application.ApplicationManager.getApplication().invokeLater {
309316
IdeaModelConfigDialogWrapper.show(
310317
project = project,
311318
currentConfig = dialogConfig,
312-
currentConfigName = currentConfigName,
319+
currentConfigName = dialogConfigName,
313320
onSave = { configName, newModelConfig ->
314321
// If creating a new config (not editing current), ensure unique name
315322
val existingNames = availableConfigs.map { it.name }

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentViewModel.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class IdeaAgentViewModel(
8181
// Show config dialog
8282
private val _showConfigDialog = MutableStateFlow(false)
8383
val showConfigDialog: StateFlow<Boolean> = _showConfigDialog.asStateFlow()
84+
private val _isNewConfig = MutableStateFlow(false)
85+
val isNewConfig: StateFlow<Boolean> = _isNewConfig.asStateFlow()
8486

8587
// Current execution job (for cancellation)
8688
private var currentJob: Job? = null
@@ -587,6 +589,22 @@ class IdeaAgentViewModel(
587589
_showConfigDialog.value = show
588590
}
589591

592+
/**
593+
* Show config dialog for adding a new config.
594+
*/
595+
fun showAddNewConfigDialog() {
596+
_isNewConfig.value = true
597+
_showConfigDialog.value = true
598+
}
599+
600+
/**
601+
* Show config dialog for editing current config.
602+
*/
603+
fun showEditConfigDialog() {
604+
_isNewConfig.value = false
605+
_showConfigDialog.value = true
606+
}
607+
590608
/**
591609
* Set the active configuration by name
592610
*/

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaDevInInputArea.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ fun IdeaDevInInputArea(
8080
currentConfigName: String? = null,
8181
onConfigSelect: (NamedModelConfig) -> Unit = {},
8282
onConfigureClick: () -> Unit = {},
83+
onAddNewConfig: () -> Unit = {},
8384
currentPlan: AgentPlan? = null
8485
) {
8586
val scope = rememberIdeaCoroutineScope(project)
@@ -116,6 +117,11 @@ fun IdeaDevInInputArea(
116117
onDispose { }
117118
}
118119

120+
DisposableEffect(onAddNewConfig) {
121+
swingInputArea?.setOnAddNewConfig(onAddNewConfig)
122+
onDispose { }
123+
}
124+
119125
DisposableEffect(currentPlan) {
120126
swingInputArea?.setCurrentPlan(currentPlan)
121127
onDispose { }
@@ -140,6 +146,7 @@ fun IdeaDevInInputArea(
140146
it.setCurrentConfigName(currentConfigName)
141147
it.setOnConfigSelect(onConfigSelect)
142148
it.setOnConfigureClick(onConfigureClick)
149+
it.setOnAddNewConfig(onAddNewConfig)
143150
it.setCurrentPlan(currentPlan)
144151
}
145152
},
@@ -327,6 +334,10 @@ class SwingDevInInputArea(
327334
bottomToolbar.setOnConfigureClick(callback)
328335
}
329336

337+
fun setOnAddNewConfig(callback: () -> Unit) {
338+
bottomToolbar.setOnAddNewConfig(callback)
339+
}
340+
330341
fun setCurrentPlan(plan: AgentPlan?) {
331342
currentPlan = plan
332343
// TODO: Add plan summary bar support

mpp-ui/src/commonMain/i18n/cc/unitmesh/devins/ui/i18n/AutoDevStrings_en.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ common.back=Back
77
common.confirm=Confirm
88
common.configure=Configure
99
common.loading=Loading
10+
common.add=Add
1011

1112
# Chat UI
1213
chat.title=AutoDev
@@ -25,6 +26,7 @@ modelConfig.temperature=Temperature
2526
modelConfig.maxTokens=Max Tokens
2627
modelConfig.advancedParameters=Advanced Parameters
2728
modelConfig.configureModel=Configure Model
29+
modelConfig.addNewConfig=Add New Config
2830
modelConfig.noSavedConfigs=No saved configurations
2931
modelConfig.enterModel=Enter or select model name
3032
modelConfig.modelHint=Select from list or type custom model name

mpp-ui/src/commonMain/i18n/cc/unitmesh/devins/ui/i18n/AutoDevStrings_zh.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ common.back=返回
77
common.confirm=确认
88
common.configure=配置
99
common.loading=加载中
10+
common.add=添加
1011

1112
# Chat UI
1213
chat.title=AutoDev
@@ -25,6 +26,7 @@ modelConfig.temperature=温度
2526
modelConfig.maxTokens=最大令牌数
2627
modelConfig.advancedParameters=高级参数
2728
modelConfig.configureModel=配置模型...
29+
modelConfig.addNewConfig=新增配置
2830
modelConfig.noSavedConfigs=没有保存的配置
2931
modelConfig.enterModel=输入或选择模型名称
3032
modelConfig.modelHint=从列表中选择或输入自定义模型名称

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/editor/ModelSelector.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import kotlinx.coroutines.launch
2727
fun ModelSelector(onConfigChange: (ModelConfig) -> Unit = {}) {
2828
var expanded by remember { mutableStateOf(false) }
2929
var showConfigDialog by remember { mutableStateOf(false) }
30+
var isNewConfig by remember { mutableStateOf(false) }
3031

3132
var availableConfigs by remember { mutableStateOf<List<NamedModelConfig>>(emptyList()) }
3233
var currentConfigName by remember { mutableStateOf<String?>(null) }
@@ -135,10 +136,28 @@ fun ModelSelector(onConfigChange: (ModelConfig) -> Unit = {}) {
135136
HorizontalDivider()
136137
}
137138

138-
// Configure button
139+
// Add New Config button
140+
DropdownMenuItem(
141+
text = { Text(Strings.addNewConfig) },
142+
onClick = {
143+
isNewConfig = true
144+
showConfigDialog = true
145+
expanded = false
146+
},
147+
leadingIcon = {
148+
Icon(
149+
imageVector = AutoDevComposeIcons.Add,
150+
contentDescription = Strings.add,
151+
modifier = Modifier.size(18.dp)
152+
)
153+
}
154+
)
155+
156+
// Configure button (edit current config)
139157
DropdownMenuItem(
140158
text = { Text(Strings.configureModel) },
141159
onClick = {
160+
isNewConfig = false
142161
showConfigDialog = true
143162
expanded = false
144163
},
@@ -154,9 +173,12 @@ fun ModelSelector(onConfigChange: (ModelConfig) -> Unit = {}) {
154173

155174
if (showConfigDialog) {
156175
ModelConfigDialog(
157-
currentConfig = currentConfig?.toModelConfig() ?: ModelConfig(),
158-
currentConfigName = currentConfigName,
159-
onDismiss = { showConfigDialog = false },
176+
currentConfig = if (isNewConfig) ModelConfig() else (currentConfig?.toModelConfig() ?: ModelConfig()),
177+
currentConfigName = if (isNewConfig) null else currentConfigName,
178+
onDismiss = {
179+
showConfigDialog = false
180+
isNewConfig = false
181+
},
160182
onSave = { configName, newModelConfig ->
161183
scope.launch {
162184
try {

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/i18n/I18n.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ object Strings {
6666
val confirm: String get() = AutoDevStrings.common_confirm.toString()
6767
val configure: String get() = AutoDevStrings.common_configure.toString()
6868
val loading: String get() = AutoDevStrings.common_loading.toString()
69+
val add: String get() = AutoDevStrings.common_add.toString()
6970

7071
// Chat UI
7172
val chatTitle: String get() = AutoDevStrings.chat_title.toString()
@@ -85,6 +86,7 @@ object Strings {
8586
val maxTokens: String get() = AutoDevStrings.modelConfig_maxTokens.toString()
8687
val advancedParameters: String get() = AutoDevStrings.modelConfig_advancedParameters.toString()
8788
val configureModel: String get() = AutoDevStrings.modelConfig_configureModel.toString()
89+
val addNewConfig: String get() = AutoDevStrings.modelConfig_addNewConfig.toString()
8890
val noSavedConfigs: String get() = AutoDevStrings.modelConfig_noSavedConfigs.toString()
8991
val enterModel: String get() = AutoDevStrings.modelConfig_enterModel.toString()
9092
val enterApiKey: String get() = AutoDevStrings.modelConfig_enterApiKey.toString()

0 commit comments

Comments
 (0)