steer_tui/tui/
core_commands.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::str::FromStr;
4
5pub use steer_grpc::client_api::CompactResult;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8#[serde(tag = "response_type", rename_all = "snake_case")]
9pub enum CommandResponse {
10 Text(String),
11 Compact(CompactResult),
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15#[serde(tag = "command_type", rename_all = "snake_case")]
16pub enum CoreCommandType {
17 Model { target: Option<String> },
18 Agent { target: Option<String> },
19 Compact,
20}
21
22impl CoreCommandType {
23 pub fn parse(input: &str) -> Result<Self, SlashCommandError> {
24 let command = input.trim();
25 let command = command.strip_prefix('/').unwrap_or(command);
26
27 let parts: Vec<&str> = command.split_whitespace().collect();
28 if parts.is_empty() {
29 return Err(SlashCommandError::InvalidFormat(
30 "Empty command".to_string(),
31 ));
32 }
33
34 match parts[0] {
35 "model" => {
36 let target = if parts.len() > 1 {
37 Some(parts[1..].join(" "))
38 } else {
39 None
40 };
41 Ok(CoreCommandType::Model { target })
42 }
43 "agent" | "mode" => {
44 let target = if parts.len() > 1 {
45 Some(parts[1..].join(" "))
46 } else {
47 None
48 };
49 Ok(CoreCommandType::Agent { target })
50 }
51 "compact" => Ok(CoreCommandType::Compact),
52 cmd => Err(SlashCommandError::UnknownCommand(cmd.to_string())),
53 }
54 }
55
56 pub fn as_command_str(&self) -> String {
57 match self {
58 CoreCommandType::Model { target } => {
59 if let Some(model) = target {
60 format!("model {model}")
61 } else {
62 "model".to_string()
63 }
64 }
65 CoreCommandType::Agent { target } => {
66 if let Some(agent) = target {
67 format!("agent {agent}")
68 } else {
69 "agent".to_string()
70 }
71 }
72 CoreCommandType::Compact => "compact".to_string(),
73 }
74 }
75}
76
77impl fmt::Display for CoreCommandType {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "/{}", self.as_command_str())
80 }
81}
82
83impl FromStr for CoreCommandType {
84 type Err = SlashCommandError;
85
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 Self::parse(s)
88 }
89}
90
91#[derive(Debug, thiserror::Error)]
92pub enum SlashCommandError {
93 #[error("Unknown command: {0}")]
94 UnknownCommand(String),
95 #[error("Invalid command format: {0}")]
96 InvalidFormat(String),
97}