Skip to content

Commit 7e4b4b9

Browse files
Address the issues
1 parent 34480af commit 7e4b4b9

2 files changed

Lines changed: 46 additions & 36 deletions

File tree

core/src/main/kotlin/org/evomaster/core/EMConfig.kt

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,36 +1534,6 @@ class EMConfig {
15341534
"Ensemble model is a combination of a comma-separated list, e.g., GLM,NN,KDE.")
15351535
var aiModelForResponseClassification: String = "NONE"
15361536

1537-
fun setAIModels(vararg models: AIResponseClassifierModel) {
1538-
aiModelForResponseClassification =
1539-
models.joinToString(",") { it.name }
1540-
}
1541-
1542-
fun getAIModelForResponseClassification(): List<AIResponseClassifierModel> {
1543-
val models = aiModelForResponseClassification
1544-
.split(",")
1545-
.map { it.trim() }
1546-
.filter { it.isNotEmpty() }
1547-
.map {
1548-
try {
1549-
AIResponseClassifierModel.valueOf(it)
1550-
} catch (e: Exception) {
1551-
throw ConfigProblemException("Invalid AI model: $it")
1552-
}
1553-
}
1554-
.distinct()
1555-
.sorted()
1556-
1557-
// EvoMaster accept NONE or a combination of the AI models and not both
1558-
if (models.contains(AIResponseClassifierModel.NONE) && models.size > 1) {
1559-
throw ConfigProblemException(
1560-
"Invalid configuration: NONE cannot be combined with other AI models"
1561-
)
1562-
}
1563-
1564-
return models
1565-
}
1566-
15671537
@Experimental
15681538
@Cfg("Learning rate controlling the step size during parameter updates in classifiers. " +
15691539
"Relevant for gradient-based models such as GLM and neural networks. " +
@@ -3274,6 +3244,7 @@ class EMConfig {
32743244

32753245
fun isEnabledAIModelForResponseClassification() = getAIModelForResponseClassification().any { it != AIResponseClassifierModel.NONE }
32763246

3247+
32773248
/**
32783249
* Source to build the final GA solution when evolving full test suites (not single tests).
32793250
* ARCHIVE: use current behavior (take tests from the archive).
@@ -3375,4 +3346,41 @@ class EMConfig {
33753346
return disabledOracleCodesList!!
33763347
}
33773348

3349+
// Sets the AI response classification models programmatically.
3350+
fun setAIModels(vararg models: AIResponseClassifierModel) {
3351+
aiModelForResponseClassification =
3352+
models.joinToString(",") { it.name }
3353+
}
3354+
3355+
/**
3356+
* Parses and validates the configured AI response classification models.
3357+
* The configuration may contain a single model (e.g., "GLM") or
3358+
* multiple models separated by commas for ensemble usage (e.g., "GLM, NN, KDE")
3359+
* The value "NONE" to disable AI-based response classification.
3360+
*/
3361+
fun getAIModelForResponseClassification(): List<AIResponseClassifierModel> {
3362+
val models = aiModelForResponseClassification
3363+
.split(",")
3364+
.map { it.trim() }
3365+
.filter { it.isNotEmpty() }
3366+
.map {
3367+
try {
3368+
AIResponseClassifierModel.valueOf(it)
3369+
} catch (e: Exception) {
3370+
throw ConfigProblemException("Invalid AI model: $it")
3371+
}
3372+
}
3373+
.distinct()
3374+
.sorted()
3375+
3376+
// EvoMaster accept NONE or a combination of the AI models and not both
3377+
if (models.contains(AIResponseClassifierModel.NONE) && models.size > 1) {
3378+
throw ConfigProblemException(
3379+
"Invalid configuration: NONE cannot be combined with other AI models"
3380+
)
3381+
}
3382+
3383+
return models
3384+
}
3385+
33783386
}

core/src/main/kotlin/org/evomaster/core/problem/rest/service/AIResponseClassifier.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,16 @@ class AIResponseClassifier : AIModel {
120120
* among all the other used models based on the average of key metrics.
121121
* For the single-model scenario, the function simply returns the single model.
122122
*/
123-
private fun selectBestModel(endpoint: Endpoint): AIModel? {
123+
private fun selectBestModel(endpoint: Endpoint): AIModel {
124+
125+
require(delegates.isNotEmpty()) {
126+
"No AI models were initialized in AIResponseClassifier for the endpoint: ${endpoint.path}"
127+
}
124128

125129
// Return the single model if there is only one delegate.
126130
if (delegates.size == 1) return delegates.first()
127131

128-
return delegates.maxByOrNull { model ->
132+
return delegates.maxBy { model ->
129133
val m = model.estimateMetrics(endpoint)
130134
listOf(
131135
m.precision400,
@@ -254,8 +258,7 @@ class AIResponseClassifier : AIModel {
254258
val start = System.nanoTime()
255259

256260
val bestModel = selectBestModel(input.endpoint)
257-
258-
val result = bestModel?.classify(input) ?: AIResponseClassification()
261+
val result = bestModel.classify(input)
259262

260263
val p = result.probabilityOf400()
261264
val invalidFields = result.invalidFields
@@ -280,8 +283,7 @@ class AIResponseClassifier : AIModel {
280283
*/
281284
override fun estimateMetrics(endpoint: Endpoint): ModelEvaluation {
282285
val bestModel = selectBestModel(endpoint)
283-
return bestModel?.estimateMetrics(endpoint)
284-
?: ModelEvaluation.DEFAULT_NO_DATA
286+
return bestModel.estimateMetrics(endpoint)
285287
}
286288

287289
/**

0 commit comments

Comments
 (0)