use runtime::{compact_session, CompactionConfig, Session}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CommandManifestEntry { pub name: String, pub source: CommandSource, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CommandSource { Builtin, InternalOnly, FeatureGated, } #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct CommandRegistry { entries: Vec, } impl CommandRegistry { #[must_use] pub fn new(entries: Vec) -> Self { Self { entries } } #[must_use] pub fn entries(&self) -> &[CommandManifestEntry] { &self.entries } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct SlashCommandResult { pub message: String, pub session: Session, } #[must_use] pub fn handle_slash_command( input: &str, session: &Session, compaction: CompactionConfig, ) -> Option { let trimmed = input.trim(); if !trimmed.starts_with('/') { return None; } match trimmed.split_whitespace().next() { Some("/compact") => { let result = compact_session(session, compaction); let message = if result.removed_message_count == 0 { "Compaction skipped: session is below the compaction threshold.".to_string() } else { format!( "Compacted {} messages into a resumable system summary.", result.removed_message_count ) }; Some(SlashCommandResult { message, session: result.compacted_session, }) } _ => None, } } #[cfg(test)] mod tests { use super::handle_slash_command; use runtime::{CompactionConfig, ContentBlock, ConversationMessage, MessageRole, Session}; #[test] fn compacts_sessions_via_slash_command() { let session = Session { version: 1, messages: vec![ ConversationMessage::user_text("a ".repeat(200)), ConversationMessage::assistant(vec![ContentBlock::Text { text: "b ".repeat(200), }]), ConversationMessage::tool_result("1", "bash", "ok ".repeat(200), false), ConversationMessage::assistant(vec![ContentBlock::Text { text: "recent".to_string(), }]), ], }; let result = handle_slash_command( "/compact", &session, CompactionConfig { preserve_recent_messages: 2, max_estimated_tokens: 1, }, ) .expect("slash command should be handled"); assert!(result.message.contains("Compacted 2 messages")); assert_eq!(result.session.messages[0].role, MessageRole::System); } #[test] fn ignores_unknown_slash_commands() { let session = Session::new(); assert!(handle_slash_command("/unknown", &session, CompactionConfig::default()).is_none()); } }