fix(model): MoA row shows 'not loaded' on null temperatures (#1421)
This commit is contained in:
3 files changed
+45
-5
No files matched your search
@@ -25,14 +25,20 @@ data class MainModelAssignment(
|
||||
data class MoaModelSlot(
|
||||
val provider: String,
|
||||
val model: String,
|
||||
val reasoning_effort: String? = null,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MoaConfigPreset(
|
||||
val reference_models: List<MoaModelSlot>,
|
||||
val aggregator: MoaModelSlot,
|
||||
val reference_temperature: Double = 0.7,
|
||||
val aggregator_temperature: Double = 0.3,
|
||||
// null = omitted from API calls (provider default); the backend sends null when unset.
|
||||
val reference_temperature: Double? = null,
|
||||
val aggregator_temperature: Double? = null,
|
||||
val reference_timeout: Double? = null,
|
||||
val degraded_reference_policy: String = "loud",
|
||||
val fanout: String? = null,
|
||||
val max_tokens: Int = 4096,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
@@ -44,8 +50,12 @@ data class MoaConfigResponse(
|
||||
val presets: Map<String, MoaConfigPreset> = emptyMap(),
|
||||
val reference_models: List<MoaModelSlot> = emptyList(),
|
||||
val aggregator: MoaModelSlot = MoaModelSlot("", ""),
|
||||
val reference_temperature: Double = 0.7,
|
||||
val aggregator_temperature: Double = 0.3,
|
||||
// null = omitted from API calls (provider default); the backend sends null when unset.
|
||||
val reference_temperature: Double? = null,
|
||||
val aggregator_temperature: Double? = null,
|
||||
val reference_timeout: Double? = null,
|
||||
val degraded_reference_policy: String = "loud",
|
||||
val fanout: String? = null,
|
||||
val max_tokens: Int = 4096,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
@@ -146,7 +147,7 @@ fun ChatLifecycleEffects(
|
||||
|
||||
// Show error as snackbar
|
||||
val clipboard = LocalClipboard.current
|
||||
val copyLabel = context.getString(R.string.action_copy_error)
|
||||
val copyLabel = stringResource(R.string.action_copy_error)
|
||||
// Own scope + immediate clear: a later `errorMessage = null` elsewhere must not cancel a visible popup.
|
||||
val snackbarScope = rememberCoroutineScope()
|
||||
LaunchedEffect(errorMessage) {
|
||||
|
||||
@@ -622,4 +622,33 @@ class ModelSerializationTest {
|
||||
json.decodeFromString<ToggleSkillRequest>(jsonInput)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun moaConfigDecodesNullTemperaturesAndNewFields() {
|
||||
val payload =
|
||||
"""
|
||||
{"default_preset":"default","active_preset":"","privacy_filter":"",
|
||||
"presets":{"default":{"enabled":true,
|
||||
"reference_models":[{"provider":"openrouter","model":"x/y","enabled":false,"reasoning_effort":"high"}],
|
||||
"aggregator":{"provider":"openrouter","model":"a/b"},
|
||||
"reference_temperature":null,"aggregator_temperature":null,
|
||||
"reference_timeout":null,"degraded_reference_policy":"silent","fanout":"every_n:3"}},
|
||||
"reference_models":[{"provider":"openrouter","model":"x/y","enabled":true}],
|
||||
"aggregator":{"provider":"openrouter","model":"a/b"},
|
||||
"reference_temperature":null,"aggregator_temperature":null,
|
||||
"reference_timeout":null,"degraded_reference_policy":"silent","fanout":"every_n:3","enabled":true}
|
||||
""".trimIndent()
|
||||
val cfg = json.decodeFromString<MoaConfigResponse>(payload)
|
||||
assertNull(cfg.reference_temperature)
|
||||
assertNull(cfg.aggregator_temperature)
|
||||
assertEquals("every_n:3", cfg.fanout)
|
||||
val preset = cfg.presets.getValue("default")
|
||||
assertEquals("silent", preset.degraded_reference_policy)
|
||||
assertEquals(false, preset.reference_models.first().enabled)
|
||||
assertEquals("high", preset.reference_models.first().reasoning_effort)
|
||||
// Round-trip keeps the non-default knobs so a save doesn't reset them.
|
||||
val back = json.encodeToString(cfg)
|
||||
assertTrue(back.contains("every_n:3"))
|
||||
assertTrue(back.contains("silent"))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user