feat(bots): increase group chat limits to 50/20 with warning banner and confirmation dialog (#1049)
This commit is contained in:
7 files changed
+180
-13
No files matched your search
@@ -42,8 +42,10 @@ import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Stop
|
||||
import androidx.compose.material.icons.filled.Terminal
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -549,6 +551,11 @@ private fun GroupChatSettingsDialog(
|
||||
var maxMessages by remember(currentMaxMessages) { mutableStateOf(currentMaxMessages.toFloat()) }
|
||||
var maxPasses by remember(currentMaxPasses) { mutableStateOf(currentMaxPasses.toFloat()) }
|
||||
var systemPrompt by remember(currentSystemPrompt) { mutableStateOf(currentSystemPrompt.orEmpty()) }
|
||||
var showHighLimitsConfirmation by remember { mutableStateOf(false) }
|
||||
|
||||
val isHighLimit =
|
||||
maxMessages.roundToInt() > WARN_MAX_BOT_MESSAGES ||
|
||||
maxPasses.roundToInt() > WARN_MAX_CONTINUATION_PASSES
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
@@ -579,7 +586,12 @@ private fun GroupChatSettingsDialog(
|
||||
Text(
|
||||
text = "${maxMessages.roundToInt()}",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
color =
|
||||
if (maxMessages.roundToInt() > WARN_MAX_BOT_MESSAGES) {
|
||||
MaterialTheme.colorScheme.error
|
||||
} else {
|
||||
MaterialTheme.colorScheme.primary
|
||||
},
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
}
|
||||
@@ -595,8 +607,8 @@ private fun GroupChatSettingsDialog(
|
||||
Slider(
|
||||
value = maxMessages,
|
||||
onValueChange = { maxMessages = it },
|
||||
valueRange = 1f..20f,
|
||||
steps = 18,
|
||||
valueRange = 1f..MAX_ALLOWED_BOT_MESSAGES.toFloat(),
|
||||
steps = MAX_ALLOWED_BOT_MESSAGES - 2,
|
||||
modifier = Modifier.testTag("max_messages_slider"),
|
||||
)
|
||||
}
|
||||
@@ -616,7 +628,12 @@ private fun GroupChatSettingsDialog(
|
||||
Text(
|
||||
text = "${maxPasses.roundToInt()}",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
color =
|
||||
if (maxPasses.roundToInt() > WARN_MAX_CONTINUATION_PASSES) {
|
||||
MaterialTheme.colorScheme.error
|
||||
} else {
|
||||
MaterialTheme.colorScheme.primary
|
||||
},
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
}
|
||||
@@ -632,12 +649,52 @@ private fun GroupChatSettingsDialog(
|
||||
Slider(
|
||||
value = maxPasses,
|
||||
onValueChange = { maxPasses = it },
|
||||
valueRange = 0f..6f,
|
||||
steps = 5,
|
||||
valueRange = 0f..MAX_ALLOWED_CONTINUATION_PASSES.toFloat(),
|
||||
steps = MAX_ALLOWED_CONTINUATION_PASSES - 1,
|
||||
modifier = Modifier.testTag("max_handoffs_slider"),
|
||||
)
|
||||
}
|
||||
|
||||
// Live In-Dialog Warning Banner (Option C)
|
||||
AnimatedVisibility(
|
||||
visible = isHighLimit,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.errorContainer.copy(alpha = 0.35f),
|
||||
contentColor = MaterialTheme.colorScheme.onErrorContainer,
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.error.copy(alpha = 0.5f)),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("high_limits_warning_banner"),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Warning,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
Text(
|
||||
text =
|
||||
stringResource(
|
||||
R.string.group_chat_settings_high_limits_warning_desc,
|
||||
maxMessages.roundToInt(),
|
||||
maxPasses.roundToInt(),
|
||||
),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Room Instructions / System Prompt
|
||||
Column {
|
||||
Text(
|
||||
@@ -674,11 +731,15 @@ private fun GroupChatSettingsDialog(
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
onSave(
|
||||
maxMessages.roundToInt(),
|
||||
maxPasses.roundToInt(),
|
||||
systemPrompt.trim().ifBlank { null },
|
||||
)
|
||||
if (isHighLimit) {
|
||||
showHighLimitsConfirmation = true
|
||||
} else {
|
||||
onSave(
|
||||
maxMessages.roundToInt(),
|
||||
maxPasses.roundToInt(),
|
||||
systemPrompt.trim().ifBlank { null },
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.testTag("save_settings_button"),
|
||||
) {
|
||||
@@ -702,6 +763,65 @@ private fun GroupChatSettingsDialog(
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (showHighLimitsConfirmation) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showHighLimitsConfirmation = false },
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Warning,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.group_chat_settings_high_limits_warning_title),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text =
|
||||
stringResource(
|
||||
R.string.group_chat_settings_high_limits_warning_desc,
|
||||
maxMessages.roundToInt(),
|
||||
maxPasses.roundToInt(),
|
||||
),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
showHighLimitsConfirmation = false
|
||||
onSave(
|
||||
maxMessages.roundToInt(),
|
||||
maxPasses.roundToInt(),
|
||||
systemPrompt.trim().ifBlank { null },
|
||||
)
|
||||
},
|
||||
colors =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.error,
|
||||
contentColor = MaterialTheme.colorScheme.onError,
|
||||
),
|
||||
modifier = Modifier.testTag("confirm_high_limits_button"),
|
||||
) {
|
||||
Text(stringResource(R.string.group_chat_settings_high_limits_confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = { showHighLimitsConfirmation = false },
|
||||
modifier = Modifier.testTag("dismiss_high_limits_button"),
|
||||
) {
|
||||
Text(stringResource(R.string.group_chat_settings_high_limits_adjust))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -52,6 +52,10 @@ data class MemberSession(
|
||||
|
||||
const val DEFAULT_MAX_BOT_MESSAGES = 6
|
||||
const val DEFAULT_MAX_CONTINUATION_PASSES = 2
|
||||
const val MAX_ALLOWED_BOT_MESSAGES = 50
|
||||
const val MAX_ALLOWED_CONTINUATION_PASSES = 20
|
||||
const val WARN_MAX_BOT_MESSAGES = 20
|
||||
const val WARN_MAX_CONTINUATION_PASSES = 6
|
||||
private const val LEASE_STEP_TTL_MS = 45_000L
|
||||
private const val TURN_TIMEOUT_MS = 45_000L
|
||||
private const val HISTORY_LIMIT = 10
|
||||
@@ -424,8 +428,8 @@ class GroupChatViewModel(
|
||||
maxPasses: Int,
|
||||
systemPrompt: String? = null,
|
||||
) {
|
||||
val clampedMessages = maxMessages.coerceIn(1, 20)
|
||||
val clampedPasses = maxPasses.coerceIn(0, 10)
|
||||
val clampedMessages = maxMessages.coerceIn(1, MAX_ALLOWED_BOT_MESSAGES)
|
||||
val clampedPasses = maxPasses.coerceIn(0, MAX_ALLOWED_CONTINUATION_PASSES)
|
||||
val cleanPrompt = systemPrompt?.trim()?.ifBlank { null }
|
||||
|
||||
_uiState.update {
|
||||
|
||||
@@ -1181,6 +1181,10 @@
|
||||
<string name="group_chat_settings_system_prompt">تعليمات / موجه الغرفة</string>
|
||||
<string name="group_chat_settings_system_prompt_hint">قواعد مخصصة، أو أسلوب، أو سياق لهذه المجموعة (اختياري)…</string>
|
||||
<string name="group_chat_settings_system_prompt_desc">إرشادات مخصصة لجميع البوتات في هذه الغرفة</string>
|
||||
<string name="group_chat_settings_high_limits_warning_title">تحذير من الحدود المرتفعة</string>
|
||||
<string name="group_chat_settings_high_limits_warning_desc">قد يؤدي تعيين حدود مرتفعة للرسائل (%1$d) أو التمريرات (%2$d) إلى استهلاك كبير للرموز (Tokens) وحدوث حلقات نقاش طويلة ومستمرة بين البوتات.</string>
|
||||
<string name="group_chat_settings_high_limits_confirm">حفظ على أي حال</string>
|
||||
<string name="group_chat_settings_high_limits_adjust">تعديل الحدود</string>
|
||||
<string name="group_chat_action_settings">الإعدادات</string>
|
||||
<string name="group_chat_stopped_by_user">تم إيقاف النقاش</string>
|
||||
<string name="group_chat_action_stop">إيقاف التوليد</string>
|
||||
|
||||
@@ -863,6 +863,10 @@
|
||||
<string name="group_chat_settings_system_prompt">방 지침 / 프롬프트</string>
|
||||
<string name="group_chat_settings_system_prompt_hint">이 그룹을 위한 사용자 지정 규칙, 어조 또는 컨텍스트 (선택사항)…</string>
|
||||
<string name="group_chat_settings_system_prompt_desc">이 방의 모든 봇에 적용되는 사용자 지정 가이드라인</string>
|
||||
<string name="group_chat_settings_high_limits_warning_title">높은 제한 경고</string>
|
||||
<string name="group_chat_settings_high_limits_warning_desc">메시지 수(%1$d) 또는 전달 횟수(%2$d)를 높게 설정하면 API 토큰이 대량 소비되고 봇 간의 긴 토론 루프가 발생할 수 있습니다.</string>
|
||||
<string name="group_chat_settings_high_limits_confirm">그래도 저장</string>
|
||||
<string name="group_chat_settings_high_limits_adjust">제한 조정</string>
|
||||
<string name="group_chat_action_settings">설정</string>
|
||||
<string name="subagent_agent_plan">에이전트 계획</string>
|
||||
<string name="subagent_live_transcript">실시간 기록</string>
|
||||
|
||||
@@ -1164,5 +1164,9 @@
|
||||
<string name="group_chat_settings_system_prompt">房间指令 / 提示词</string>
|
||||
<string name="group_chat_settings_system_prompt_hint">此群聊的自定义规则、语气或上下文(可选)…</string>
|
||||
<string name="group_chat_settings_system_prompt_desc">适用于此房间内所有 Bot 的自定义准则</string>
|
||||
<string name="group_chat_settings_high_limits_warning_title">高上限警告</string>
|
||||
<string name="group_chat_settings_high_limits_warning_desc">设置较高的消息数 (%1$d) 或交接次数 (%2$d) 可能会消耗大量 API 令牌,并导致机器人之间产生长时间的连续讨论循环。</string>
|
||||
<string name="group_chat_settings_high_limits_confirm">仍要保存</string>
|
||||
<string name="group_chat_settings_high_limits_adjust">调整限制</string>
|
||||
<string name="group_chat_action_settings">设置</string>
|
||||
</resources>
|
||||
@@ -1295,6 +1295,10 @@
|
||||
<string name="group_chat_settings_system_prompt">Room Instructions / Prompt</string>
|
||||
<string name="group_chat_settings_system_prompt_hint">Custom rules, tone, or context for this group (optional)…</string>
|
||||
<string name="group_chat_settings_system_prompt_desc">Custom guidelines for all bots in this room</string>
|
||||
<string name="group_chat_settings_high_limits_warning_title">High Limits Warning</string>
|
||||
<string name="group_chat_settings_high_limits_warning_desc">Setting high message (%1$d) or handoff (%2$d) limits can consume significant API tokens and lead to long continuous bot discussion loops.</string>
|
||||
<string name="group_chat_settings_high_limits_confirm">Save Anyway</string>
|
||||
<string name="group_chat_settings_high_limits_adjust">Adjust Limits</string>
|
||||
<string name="group_chat_action_settings">Settings</string>
|
||||
<string name="group_chat_stopped_by_user">Discussion stopped</string>
|
||||
<string name="group_chat_action_stop">Stop generation</string>
|
||||
|
||||
@@ -420,6 +420,33 @@ class GroupChatViewModelTest {
|
||||
assertEquals(15, viewModel.uiState.value.maxBotMessages)
|
||||
assertEquals(4, viewModel.uiState.value.maxContinuationPasses)
|
||||
assertEquals("Custom instructions for this group", viewModel.uiState.value.systemPrompt)
|
||||
|
||||
// Extended limits within new range
|
||||
viewModel.updateGroupLimits(
|
||||
maxMessages = 45,
|
||||
maxPasses = 18,
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
assertEquals(45, viewModel.uiState.value.maxBotMessages)
|
||||
assertEquals(18, viewModel.uiState.value.maxContinuationPasses)
|
||||
|
||||
// Exceeding ceiling clamps to MAX_ALLOWED_BOT_MESSAGES (50) and MAX_ALLOWED_CONTINUATION_PASSES (20)
|
||||
viewModel.updateGroupLimits(
|
||||
maxMessages = 999,
|
||||
maxPasses = 999,
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
assertEquals(MAX_ALLOWED_BOT_MESSAGES, viewModel.uiState.value.maxBotMessages)
|
||||
assertEquals(MAX_ALLOWED_CONTINUATION_PASSES, viewModel.uiState.value.maxContinuationPasses)
|
||||
|
||||
// Under floor clamps to 1 and 0
|
||||
viewModel.updateGroupLimits(
|
||||
maxMessages = -10,
|
||||
maxPasses = -5,
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
assertEquals(1, viewModel.uiState.value.maxBotMessages)
|
||||
assertEquals(0, viewModel.uiState.value.maxContinuationPasses)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user