* feat(#216): dynamic command autocomplete from server catalog, remove stop button - Replace hardcoded 8-command autocomplete with dynamic catalog from server's commands.catalog RPC - Show ALL commands including skills via commandCatalog.pairs - Remove physical Stop button (use /stop or /interrupt slash commands instead) - Remove onInterrupt callback from ChatInputBar * fix(#216): hide /stop and /interrupt from slash suggestions, remove stale strings - Filters /stop and /interrupt from autocomplete popup while keeping them functional when manually typed - Drops 7 unused command description string resources (now from server catalog) plus unused interrupt string resource --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
85c4662537
commit
96e754dd3b
2 files changed
+11
-56
No files matched your search
@@ -54,14 +54,12 @@ import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Stop
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.FilledTonalIconButton
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -106,6 +104,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.m57.hermescontrol.NavigationController
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.data.ws.CommandCatalog
|
||||
import com.m57.hermescontrol.data.ws.ConnectionStatus
|
||||
import com.m57.hermescontrol.notification.NotificationHelper
|
||||
import com.m57.hermescontrol.theme.StatusRed
|
||||
@@ -294,9 +293,9 @@ fun ChatScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onInterrupt = viewModel::interruptSession,
|
||||
isAgentTyping = state.isAgentTyping,
|
||||
isConnected = state.isConnected,
|
||||
commandCatalog = state.commandCatalog,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -365,9 +364,9 @@ private fun ChatInputBar(
|
||||
inputText: String,
|
||||
onInputChange: (String) -> Unit,
|
||||
onSend: () -> Unit,
|
||||
onInterrupt: () -> Unit,
|
||||
isAgentTyping: Boolean,
|
||||
isConnected: Boolean,
|
||||
commandCatalog: CommandCatalog,
|
||||
) {
|
||||
// Allow sending slash commands even while agent is typing
|
||||
val isSlashCommand = inputText.startsWith("/")
|
||||
@@ -396,23 +395,18 @@ private fun ChatInputBar(
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp),
|
||||
) {
|
||||
Column {
|
||||
val commands =
|
||||
listOf(
|
||||
"/help",
|
||||
"/status",
|
||||
"/sessions",
|
||||
"/stats",
|
||||
"/system",
|
||||
"/new",
|
||||
"/stop",
|
||||
"/interrupt",
|
||||
)
|
||||
// Build command list from dynamic catalog (pairs = [name, description])
|
||||
val allCommands = commandCatalog.pairs.associate { (name, desc) -> name to desc }
|
||||
// Commands hidden from suggestion menu (still work when manually typed)
|
||||
val hiddenSlashDisplay = setOf("/stop", "/interrupt")
|
||||
val commandNames = allCommands.keys.filter { it !in hiddenSlashDisplay }
|
||||
|
||||
androidx.compose.animation.AnimatedVisibility(
|
||||
visible = inputText.startsWith("/") && !inputText.contains(" "),
|
||||
enter = androidx.compose.animation.fadeIn() + androidx.compose.animation.expandVertically(),
|
||||
exit = androidx.compose.animation.fadeOut() + androidx.compose.animation.shrinkVertically(),
|
||||
) {
|
||||
val filteredCommands = commands.filter { it.startsWith(inputText, ignoreCase = true) }
|
||||
val filteredCommands = commandNames.filter { it.startsWith(inputText, ignoreCase = true) }
|
||||
if (filteredCommands.isNotEmpty()) {
|
||||
androidx.compose.material3.Surface(
|
||||
modifier =
|
||||
@@ -431,18 +425,7 @@ private fun ChatInputBar(
|
||||
modifier = Modifier.heightIn(max = 200.dp),
|
||||
) {
|
||||
items(filteredCommands, key = { it }) { cmd ->
|
||||
val description =
|
||||
when (cmd) {
|
||||
"/help" -> stringResource(R.string.command_help_desc)
|
||||
"/status" -> stringResource(R.string.command_status_desc)
|
||||
"/sessions" -> stringResource(R.string.command_sessions_desc)
|
||||
"/stats" -> stringResource(R.string.command_stats_desc)
|
||||
"/system" -> stringResource(R.string.command_system_desc)
|
||||
"/new" -> stringResource(R.string.command_new_desc)
|
||||
"/stop" -> stringResource(R.string.command_stop_desc)
|
||||
"/interrupt" -> stringResource(R.string.command_stop_desc)
|
||||
else -> ""
|
||||
}
|
||||
val description = allCommands[cmd] ?: ""
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(
|
||||
@@ -527,26 +510,6 @@ private fun ChatInputBar(
|
||||
contentDescription = stringResource(R.string.chat_send_desc),
|
||||
)
|
||||
}
|
||||
|
||||
// Compact stop icon — visible only while agent is streaming
|
||||
if (isAgentTyping) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
FilledTonalIconButton(
|
||||
onClick = onInterrupt,
|
||||
modifier =
|
||||
Modifier
|
||||
.size(32.dp)
|
||||
.testTag("interrupt_button"),
|
||||
shape = CircleShape,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Stop,
|
||||
contentDescription = stringResource(R.string.content_desc_interrupt),
|
||||
modifier = Modifier.size(18.dp),
|
||||
tint = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user