Skip to main content

steer_tui/tui/
core_commands.rs

1use 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}