use crate::agent::context_compressor::estimate_tokens; use crate::command::context::CommandContext; use crate::command::handler::{CommandHandler, CommandMetadata}; use crate::command::handlers::get_messages_from_session; use crate::command::response::{CommandError, CommandResponse, MessageKind}; use crate::command::Command; use crate::gateway::session::SessionManager; use crate::storage::SessionStore; use async_trait::async_trait; use std::sync::Arc; /// 获取当前话题命令处理器 pub struct GetCurrentSessionCommandHandler { store: Arc, session_manager: Option, } impl GetCurrentSessionCommandHandler { pub fn new(store: Arc) -> Self { Self { store, session_manager: None, } } pub fn with_session_manager(mut self, session_manager: SessionManager) -> Self { self.session_manager = Some(session_manager); self } } #[async_trait] impl CommandHandler for GetCurrentSessionCommandHandler { fn can_handle(&self, cmd: &Command) -> bool { matches!(cmd, Command::GetCurrentSession) } fn metadata(&self) -> Option { Some(CommandMetadata { name: "current", description: "获取当前话题信息", usage: "/current", }) } async fn handle( &self, cmd: Command, ctx: CommandContext, ) -> Result { match cmd { Command::GetCurrentSession => handle_get_current_session(self, ctx).await, _ => unreachable!(), } } } async fn handle_get_current_session( handler: &GetCurrentSessionCommandHandler, ctx: CommandContext, ) -> Result { let topic_id = ctx.topic_id.as_deref() .ok_or_else(|| CommandError::new("NO_CURRENT_TOPIC", "No current topic"))?; let chat_id = ctx.chat_id.as_deref() .ok_or_else(|| CommandError::new("NO_CHAT_ID", "No chat id".to_string()))?; let topic = handler .store .get_topic(topic_id) .map_err(|e| CommandError::new("GET_TOPIC_ERROR", e.to_string()))? .ok_or_else(|| CommandError::new("TOPIC_NOT_FOUND", format!("Topic not found: {}", topic_id)))?; // Load messages from session memory let messages = get_messages_from_session( &handler.session_manager, &ctx.channel_name, chat_id, ).await?; let actual_message_count = messages.len(); let estimated_tokens = estimate_tokens(&messages); let last_active = format_time_ago(topic.last_active_at); let created_at = format_time_ago(topic.created_at); let message = format!( "Current Topic:\n\n Topic ID: {}\n Title: {}\n Messages: {}\n Tokens: ~{}\n Created: {}\n Last Active: {}", topic.id, topic.title, actual_message_count, estimated_tokens, created_at, last_active ); Ok(CommandResponse::success(ctx.request_id) .with_message(MessageKind::Notification, &message) .with_metadata("topic_id", &topic.id) .with_metadata("title", &topic.title) .with_metadata("message_count", &actual_message_count.to_string()) .with_metadata("estimated_tokens", &estimated_tokens.to_string())) } fn format_time_ago(timestamp_ms: i64) -> String { let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_millis() as i64; let diff_ms = now - timestamp_ms; let diff_secs = diff_ms / 1000; if diff_secs < 60 { "just now".to_string() } else if diff_secs < 3600 { format!("{} mins ago", diff_secs / 60) } else if diff_secs < 86400 { format!("{} hours ago", diff_secs / 3600) } else { format!("{} days ago", diff_secs / 86400) } }