@@ -60,10 +60,10 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
60
60
// Category section panel for dynamic visibility
61
61
private var categoryPanel: JPanel ? = null
62
62
63
- // Model management - simplified table with only Name and ID
64
- private val llmTableModel = object : DefaultTableModel (arrayOf(" Name" , " ID " , " Delete" ), 0 ) {
63
+ // Model management - table with Name, Model, Streaming, Temperature, Delete
64
+ private val llmTableModel = object : DefaultTableModel (arrayOf(" Name" , " Model " , " Streaming " , " Temperature " , " Delete" ), 0 ) {
65
65
override fun isCellEditable (row : Int , column : Int ): Boolean {
66
- return column == 2 // Only delete column is "editable" (clickable)
66
+ return column == 4 // Only delete column is "editable" (clickable)
67
67
}
68
68
}
69
69
private val llmTable = JTable (llmTableModel)
@@ -140,19 +140,21 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
140
140
val row = llmTable.rowAtPoint(e.point)
141
141
val column = llmTable.columnAtPoint(e.point)
142
142
143
- // Only allow double-click on Name or ID columns (not Delete column)
144
- if (row >= 0 && column < 2 ) {
143
+ // Only allow double-click on Name, Model, Streaming, Temperature columns (not Delete column)
144
+ if (row >= 0 && column < 4 ) {
145
145
editLLMAtRow(row)
146
146
}
147
147
}
148
148
}
149
149
})
150
150
151
151
// Set column widths
152
- llmTable.columnModel.getColumn(0 ).preferredWidth = 200 // Name
153
- llmTable.columnModel.getColumn(1 ).preferredWidth = 300 // ID
154
- llmTable.columnModel.getColumn(2 ).preferredWidth = 80 // Delete
155
- llmTable.columnModel.getColumn(2 ).maxWidth = 80
152
+ llmTable.columnModel.getColumn(0 ).preferredWidth = 150 // Name
153
+ llmTable.columnModel.getColumn(1 ).preferredWidth = 200 // Model
154
+ llmTable.columnModel.getColumn(2 ).preferredWidth = 80 // Streaming
155
+ llmTable.columnModel.getColumn(3 ).preferredWidth = 100 // Temperature
156
+ llmTable.columnModel.getColumn(4 ).preferredWidth = 80 // Delete
157
+ llmTable.columnModel.getColumn(4 ).maxWidth = 80
156
158
}
157
159
158
160
private fun markAsModified () {
@@ -192,7 +194,11 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
192
194
private val tokenField = JBTextField ()
193
195
private val maxTokensField = JBTextField ()
194
196
private val modelTypeComboBox = JComboBox (ModelType .values())
197
+
198
+ // Explicit model parameters
199
+ private val modelField = JBTextField ()
195
200
private val streamCheckbox = JBCheckBox (" Use streaming response" , true )
201
+ private val temperatureField = JBTextField ()
196
202
197
203
// Custom headers and body fields
198
204
private val headersArea = JTextArea (3 , 40 )
@@ -212,7 +218,24 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
212
218
modelTypeComboBox.selectedItem = existingLlm.modelType
213
219
streamCheckbox.isSelected = existingLlm.customRequest.stream
214
220
215
- // Initialize custom headers and body
221
+ // Extract model and temperature from body
222
+ val modelValue = existingLlm.customRequest.body[" model" ]?.let {
223
+ when (it) {
224
+ is JsonPrimitive -> it.content
225
+ else -> it.toString().removeSurrounding(" \" " )
226
+ }
227
+ } ? : " "
228
+ modelField.text = modelValue
229
+
230
+ val temperatureValue = existingLlm.customRequest.body[" temperature" ]?.let {
231
+ when (it) {
232
+ is JsonPrimitive -> it.content
233
+ else -> it.toString()
234
+ }
235
+ } ? : " 0.0"
236
+ temperatureField.text = temperatureValue
237
+
238
+ // Initialize custom headers and body (excluding model and temperature)
216
239
headersArea.text = if (existingLlm.customRequest.headers.isNotEmpty()) {
217
240
buildJsonObject {
218
241
existingLlm.customRequest.headers.forEach { (key, value) ->
@@ -223,29 +246,34 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
223
246
" {}"
224
247
}
225
248
226
- bodyArea.text = if (existingLlm.customRequest.body.isNotEmpty()) {
227
- // Convert body map to JSON string
249
+ // Body without model and temperature (they are now explicit fields)
250
+ val bodyWithoutModelTemp = existingLlm.customRequest.body.filterKeys {
251
+ it != " model" && it != " temperature" && it != " stream"
252
+ }
253
+ bodyArea.text = if (bodyWithoutModelTemp.isNotEmpty()) {
228
254
buildJsonObject {
229
- existingLlm.customRequest.body .forEach { (key, value) ->
255
+ bodyWithoutModelTemp .forEach { (key, value) ->
230
256
put(key, value)
231
257
}
232
258
}.toString()
233
259
} else {
234
- """ {"model": "gpt-3.5-turbo", "temperature": 0.0} "" "
260
+ " {} "
235
261
}
236
262
} else {
237
263
// Default values for new LLM
238
264
maxTokensField.text = " 4096"
265
+ modelField.text = " gpt-3.5-turbo"
266
+ temperatureField.text = " 0.0"
239
267
headersArea.text = " {}"
240
- bodyArea.text = """ {"model": "gpt-3.5-turbo", "temperature": 0.0} "" "
268
+ bodyArea.text = " {} "
241
269
}
242
270
243
271
init ()
244
272
}
245
273
246
274
override fun createCenterPanel (): JPanel {
247
275
val panel = JPanel (BorderLayout ())
248
- panel.preferredSize = Dimension (600 , 600 )
276
+ panel.preferredSize = Dimension (600 , 700 )
249
277
250
278
val formBuilder = FormBuilder .createFormBuilder()
251
279
.addLabeledComponent(JBLabel (" Name:" ), nameField)
@@ -254,14 +282,20 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
254
282
.addLabeledComponent(JBLabel (" Token (optional):" ), tokenField)
255
283
.addLabeledComponent(JBLabel (" Max Tokens:" ), maxTokensField)
256
284
.addLabeledComponent(JBLabel (" Model Type:" ), modelTypeComboBox)
257
- .addComponent(streamCheckbox)
258
285
.addSeparator()
259
286
287
+ // Model parameters section
288
+ formBuilder.addLabeledComponent(JBLabel (" Model Parameters" ), JPanel (), 1 , false )
289
+ formBuilder.addLabeledComponent(JBLabel (" Model:" ), modelField)
290
+ formBuilder.addComponent(streamCheckbox)
291
+ formBuilder.addLabeledComponent(JBLabel (" Temperature:" ), temperatureField)
292
+ formBuilder.addSeparator()
293
+
260
294
// Custom headers section
261
295
formBuilder.addLabeledComponent(JBLabel (" Custom Headers (JSON):" ), JScrollPane (headersArea))
262
296
263
- // Custom body section
264
- formBuilder.addLabeledComponent(JBLabel (" Request Body (JSON):" ), JScrollPane (bodyArea))
297
+ // Custom body section (additional fields)
298
+ formBuilder.addLabeledComponent(JBLabel (" Additional Request Body (JSON):" ), JScrollPane (bodyArea))
265
299
266
300
formBuilder.addSeparator()
267
301
@@ -276,8 +310,8 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
276
310
}
277
311
278
312
private fun testConnection () {
279
- if (nameField.text.isBlank() || urlField.text.isBlank()) {
280
- testResultLabel.text = " Name and URL are required"
313
+ if (nameField.text.isBlank() || urlField.text.isBlank() || modelField.text.isBlank() ) {
314
+ testResultLabel.text = " Name, URL, and Model are required"
281
315
testResultLabel.foreground = JBColor .RED
282
316
return
283
317
}
@@ -291,13 +325,22 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
291
325
return
292
326
}
293
327
328
+ // Validate temperature
329
+ val temperature = try {
330
+ temperatureField.text.toDouble()
331
+ } catch (e: NumberFormatException ) {
332
+ testResultLabel.text = " Temperature must be a valid number"
333
+ testResultLabel.foreground = JBColor .RED
334
+ return
335
+ }
336
+
294
337
testResultLabel.text = " Testing connection..."
295
338
testResultLabel.foreground = JBColor .BLUE
296
339
297
340
val scope = CoroutineScope (CoroutineName (" testConnection" ))
298
341
scope.launch {
299
342
try {
300
- // Parse custom headers and body
343
+ // Parse custom headers
301
344
val headers = try {
302
345
if (headersArea.text.trim().isNotEmpty() && headersArea.text.trim() != " {}" ) {
303
346
Json .decodeFromString<Map <String , String >>(headersArea.text)
@@ -312,25 +355,34 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
312
355
return @launch
313
356
}
314
357
315
- val body = try {
316
- if (bodyArea.text.trim().isNotEmpty()) {
358
+ // Parse additional body fields and combine with explicit parameters
359
+ val additionalBody = try {
360
+ if (bodyArea.text.trim().isNotEmpty() && bodyArea.text.trim() != " {}" ) {
317
361
val jsonElement = Json .parseToJsonElement(bodyArea.text)
318
362
if (jsonElement is JsonObject ) {
319
363
jsonElement.toMap()
320
364
} else {
321
- mapOf ( " model " to JsonPrimitive (nameField.text), " temperature " to JsonPrimitive ( 0.0 ) )
365
+ emptyMap( )
322
366
}
323
367
} else {
324
- mapOf ( " model " to JsonPrimitive (nameField.text), " temperature " to JsonPrimitive ( 0.0 ) )
368
+ emptyMap( )
325
369
}
326
370
} catch (e: Exception ) {
327
371
SwingUtilities .invokeLater {
328
- testResultLabel.text = " Invalid body JSON: ${e.message} "
372
+ testResultLabel.text = " Invalid additional body JSON: ${e.message} "
329
373
testResultLabel.foreground = JBColor .RED
330
374
}
331
375
return @launch
332
376
}
333
377
378
+ // Combine explicit parameters with additional body
379
+ val body = mutableMapOf<String , JsonElement >().apply {
380
+ put(" model" , JsonPrimitive (modelField.text))
381
+ put(" temperature" , JsonPrimitive (temperature))
382
+ put(" stream" , JsonPrimitive (streamCheckbox.isSelected))
383
+ putAll(additionalBody)
384
+ }
385
+
334
386
// Create a temporary LLM config for testing
335
387
val customRequest = CustomRequest (
336
388
headers = headers,
@@ -378,8 +430,8 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
378
430
}
379
431
380
432
override fun doOKAction () {
381
- if (nameField.text.isBlank() || urlField.text.isBlank()) {
382
- Messages .showErrorDialog(" Name and URL are required" , " Validation Error" )
433
+ if (nameField.text.isBlank() || urlField.text.isBlank() || modelField.text.isBlank() ) {
434
+ Messages .showErrorDialog(" Name, URL, and Model are required" , " Validation Error" )
383
435
return
384
436
}
385
437
@@ -391,8 +443,16 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
391
443
return
392
444
}
393
445
446
+ // Validate temperature
447
+ val temperature = try {
448
+ temperatureField.text.toDouble()
449
+ } catch (e: NumberFormatException ) {
450
+ Messages .showErrorDialog(" Temperature must be a valid number" , " Validation Error" )
451
+ return
452
+ }
453
+
394
454
try {
395
- // Parse custom headers and body
455
+ // Parse custom headers
396
456
val headers = try {
397
457
if (headersArea.text.trim().isNotEmpty() && headersArea.text.trim() != " {}" ) {
398
458
Json .decodeFromString<Map <String , String >>(headersArea.text)
@@ -404,22 +464,31 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
404
464
return
405
465
}
406
466
407
- val body = try {
408
- if (bodyArea.text.trim().isNotEmpty()) {
467
+ // Parse additional body fields and combine with explicit parameters
468
+ val additionalBody = try {
469
+ if (bodyArea.text.trim().isNotEmpty() && bodyArea.text.trim() != " {}" ) {
409
470
val jsonElement = Json .parseToJsonElement(bodyArea.text)
410
471
if (jsonElement is JsonObject ) {
411
472
jsonElement.toMap()
412
473
} else {
413
- mapOf ( " model " to JsonPrimitive (nameField.text), " temperature " to JsonPrimitive ( 0.0 ) )
474
+ emptyMap( )
414
475
}
415
476
} else {
416
- mapOf ( " model " to JsonPrimitive (nameField.text), " temperature " to JsonPrimitive ( 0.0 ) )
477
+ emptyMap( )
417
478
}
418
479
} catch (e: Exception ) {
419
- Messages .showErrorDialog(" Invalid body JSON: ${e.message} " , " Validation Error" )
480
+ Messages .showErrorDialog(" Invalid additional body JSON: ${e.message} " , " Validation Error" )
420
481
return
421
482
}
422
483
484
+ // Combine explicit parameters with additional body
485
+ val body = mutableMapOf<String , JsonElement >().apply {
486
+ put(" model" , JsonPrimitive (modelField.text))
487
+ put(" temperature" , JsonPrimitive (temperature))
488
+ put(" stream" , JsonPrimitive (streamCheckbox.isSelected))
489
+ putAll(additionalBody)
490
+ }
491
+
423
492
// Get existing LLMs
424
493
val existingLlms = try {
425
494
LlmConfig .load().toMutableList()
@@ -575,23 +644,41 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
575
644
val githubModels = manager.getSupportedModels(forceRefresh = false )
576
645
val userModels = LlmConfig .load()
577
646
578
- // Add GitHub Copilot models (read-only) - simplified display
647
+ // Add GitHub Copilot models (read-only)
579
648
githubModels?.forEach { model ->
580
649
llmTableModel.addRow(
581
650
arrayOf(
582
- " Github: ${model.id} " , // Name - show as "Github: model.id"
583
- model.id, // ID
651
+ " Github: ${model.id} " , // Name
652
+ model.id, // Model
653
+ " true" , // Streaming (GitHub models use streaming by default)
654
+ " 0.1" , // Temperature (GitHub models default temperature)
584
655
" " // Delete (empty for read-only models)
585
656
)
586
657
)
587
658
}
588
659
589
- // Add custom LLMs (editable) - simplified display
660
+ // Add custom LLMs (editable)
590
661
userModels.forEach { llm ->
662
+ val modelValue = llm.customRequest.body[" model" ]?.let {
663
+ when (it) {
664
+ is JsonPrimitive -> it.content
665
+ else -> it.toString().removeSurrounding(" \" " )
666
+ }
667
+ } ? : " "
668
+
669
+ val temperatureValue = llm.customRequest.body[" temperature" ]?.let {
670
+ when (it) {
671
+ is JsonPrimitive -> it.content
672
+ else -> it.toString()
673
+ }
674
+ } ? : " 0.0"
675
+
591
676
llmTableModel.addRow(
592
677
arrayOf(
593
678
llm.name, // Name
594
- llm.name, // ID (use name as ID for custom models)
679
+ modelValue, // Model
680
+ llm.customRequest.stream.toString(), // Streaming
681
+ temperatureValue, // Temperature
595
682
" Delete" // Delete button placeholder
596
683
)
597
684
)
@@ -768,11 +855,17 @@ class SimplifiedLLMSettingComponent(private val settings: AutoDevSettingsState)
768
855
// Add category panel (visibility controlled dynamically)
769
856
formBuilder.addComponent(categoryPanel!! )
770
857
858
+ // Create a properly sized scroll pane for the table
859
+ val tableScrollPane = JScrollPane (llmTable).apply {
860
+ preferredSize = Dimension (600 , 200 )
861
+ minimumSize = Dimension (400 , 150 )
862
+ }
863
+
771
864
formBuilder
772
865
// Model Management Section
773
866
.addLabeledComponent(JBLabel (" Model Management" ), JPanel (), 1 , false )
774
867
.addComponent(buttonPanel)
775
- .addComponentFillVertically(JScrollPane (llmTable) , 0 )
868
+ .addComponentFillVertically(tableScrollPane , 0 )
776
869
.addComponentFillVertically(JPanel (), 0 )
777
870
778
871
// Set initial visibility
0 commit comments