* 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.KeyboardArrowDown
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.filled.Stop
|
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material3.FilledTonalButton
|
||||||
import androidx.compose.material3.FilledTonalIconButton
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -106,6 +104,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.m57.hermescontrol.NavigationController
|
import com.m57.hermescontrol.NavigationController
|
||||||
import com.m57.hermescontrol.R
|
import com.m57.hermescontrol.R
|
||||||
|
import com.m57.hermescontrol.data.ws.CommandCatalog
|
||||||
import com.m57.hermescontrol.data.ws.ConnectionStatus
|
import com.m57.hermescontrol.data.ws.ConnectionStatus
|
||||||
import com.m57.hermescontrol.notification.NotificationHelper
|
import com.m57.hermescontrol.notification.NotificationHelper
|
||||||
import com.m57.hermescontrol.theme.StatusRed
|
import com.m57.hermescontrol.theme.StatusRed
|
||||||
@@ -294,9 +293,9 @@ fun ChatScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onInterrupt = viewModel::interruptSession,
|
|
||||||
isAgentTyping = state.isAgentTyping,
|
isAgentTyping = state.isAgentTyping,
|
||||||
isConnected = state.isConnected,
|
isConnected = state.isConnected,
|
||||||
|
commandCatalog = state.commandCatalog,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,9 +364,9 @@ private fun ChatInputBar(
|
|||||||
inputText: String,
|
inputText: String,
|
||||||
onInputChange: (String) -> Unit,
|
onInputChange: (String) -> Unit,
|
||||||
onSend: () -> Unit,
|
onSend: () -> Unit,
|
||||||
onInterrupt: () -> Unit,
|
|
||||||
isAgentTyping: Boolean,
|
isAgentTyping: Boolean,
|
||||||
isConnected: Boolean,
|
isConnected: Boolean,
|
||||||
|
commandCatalog: CommandCatalog,
|
||||||
) {
|
) {
|
||||||
// Allow sending slash commands even while agent is typing
|
// Allow sending slash commands even while agent is typing
|
||||||
val isSlashCommand = inputText.startsWith("/")
|
val isSlashCommand = inputText.startsWith("/")
|
||||||
@@ -396,23 +395,18 @@ private fun ChatInputBar(
|
|||||||
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp),
|
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp),
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
val commands =
|
// Build command list from dynamic catalog (pairs = [name, description])
|
||||||
listOf(
|
val allCommands = commandCatalog.pairs.associate { (name, desc) -> name to desc }
|
||||||
"/help",
|
// Commands hidden from suggestion menu (still work when manually typed)
|
||||||
"/status",
|
val hiddenSlashDisplay = setOf("/stop", "/interrupt")
|
||||||
"/sessions",
|
val commandNames = allCommands.keys.filter { it !in hiddenSlashDisplay }
|
||||||
"/stats",
|
|
||||||
"/system",
|
|
||||||
"/new",
|
|
||||||
"/stop",
|
|
||||||
"/interrupt",
|
|
||||||
)
|
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
visible = inputText.startsWith("/") && !inputText.contains(" "),
|
visible = inputText.startsWith("/") && !inputText.contains(" "),
|
||||||
enter = androidx.compose.animation.fadeIn() + androidx.compose.animation.expandVertically(),
|
enter = androidx.compose.animation.fadeIn() + androidx.compose.animation.expandVertically(),
|
||||||
exit = androidx.compose.animation.fadeOut() + androidx.compose.animation.shrinkVertically(),
|
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()) {
|
if (filteredCommands.isNotEmpty()) {
|
||||||
androidx.compose.material3.Surface(
|
androidx.compose.material3.Surface(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -431,18 +425,7 @@ private fun ChatInputBar(
|
|||||||
modifier = Modifier.heightIn(max = 200.dp),
|
modifier = Modifier.heightIn(max = 200.dp),
|
||||||
) {
|
) {
|
||||||
items(filteredCommands, key = { it }) { cmd ->
|
items(filteredCommands, key = { it }) { cmd ->
|
||||||
val description =
|
val description = allCommands[cmd] ?: ""
|
||||||
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 -> ""
|
|
||||||
}
|
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = {
|
text = {
|
||||||
Row(
|
Row(
|
||||||
@@ -527,26 +510,6 @@ private fun ChatInputBar(
|
|||||||
contentDescription = stringResource(R.string.chat_send_desc),
|
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,16 +91,8 @@
|
|||||||
<string name="chat_tool_fallback">Tool</string>
|
<string name="chat_tool_fallback">Tool</string>
|
||||||
<string name="chat_tool_show_raw">Show Raw JSON</string>
|
<string name="chat_tool_show_raw">Show Raw JSON</string>
|
||||||
<string name="chat_tool_show_parsed">Show Parsed Output</string>
|
<string name="chat_tool_show_parsed">Show Parsed Output</string>
|
||||||
<string name="command_help_desc">Show help menu</string>
|
|
||||||
<string name="command_status_desc">Check gateway and platform status</string>
|
|
||||||
<string name="command_sessions_desc">List all chat sessions</string>
|
|
||||||
<string name="command_stats_desc">Check system resource usage (stats)</string>
|
|
||||||
<string name="command_system_desc">Check system resource usage (system)</string>
|
|
||||||
<string name="command_new_desc">Create a new chat session</string>
|
|
||||||
<string name="command_stop_desc">Interrupt the active run</string>
|
|
||||||
<string name="content_desc_new_chat">New Chat</string>
|
<string name="content_desc_new_chat">New Chat</string>
|
||||||
<string name="content_desc_scroll_to_bottom">Scroll to bottom</string>
|
<string name="content_desc_scroll_to_bottom">Scroll to bottom</string>
|
||||||
<string name="content_desc_interrupt">Interrupt</string>
|
|
||||||
<string name="content_desc_copy">Copy</string>
|
<string name="content_desc_copy">Copy</string>
|
||||||
<string name="content_desc_edit">Edit</string>
|
<string name="content_desc_edit">Edit</string>
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user