From a3d8ebb53487fba3f6741ed82d29ce53d2af9338 Mon Sep 17 00:00:00 2001 From: xiaoxixi Date: Tue, 28 Apr 2026 20:54:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20/dump=20=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=EF=BC=8C=E5=AF=BC=E5=87=BA=20session=20=E4=B8=BA=20markdown=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /dump 命令会输出当前 session 的完整信息: - Session 元信息 (ID, channel, chat_id, model 等) - 所有对话历史 (system, user, assistant, tool) - 每条消息包含角色、时间戳、内容、工具调用等 --- src/session/session.rs | 80 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/session/session.rs b/src/session/session.rs index ca7619f..be3a403 100644 --- a/src/session/session.rs +++ b/src/session/session.rs @@ -142,6 +142,71 @@ impl Session { format!("{}\n\n## Skills\n\n{}\n\nUse the `get_skill` tool to load a skill's full content when needed.", base_prompt, skills_prompt) } } + + /// 将当前 session 导出为 markdown 文档 + pub fn dump_as_markdown(&self) -> String { + use chrono::{DateTime, Local}; + + let now = Local::now().format("%Y-%m-%d %H:%M:%S"); + + let mut md = String::new(); + md.push_str(&format!("# Session Dump\n\n")); + md.push_str(&format!("- **Session ID**: `{}`\n", self.id)); + md.push_str(&format!("- **Channel**: `{}`\n", self.id.channel)); + md.push_str(&format!("- **Chat ID**: `{}`\n", self.id.chat_id)); + md.push_str(&format!("- **Dialog ID**: `{}`\n", self.id.dialog_id)); + md.push_str(&format!("- **Message Count**: {}\n", self.messages.len())); + md.push_str(&format!("- **Model**: `{}`\n", self.provider_config.model_id)); + md.push_str(&format!("- **Exported At**: {}\n", now)); + md.push_str("\n---\n\n"); + + md.push_str("## Conversation History\n\n"); + + for (i, msg) in self.messages.iter().enumerate() { + let role = match msg.role.as_str() { + "system" => "System", + "user" => "User", + "assistant" => "Assistant", + "tool" => "Tool", + r => r, + }; + + let timestamp = if msg.timestamp > 0 { + DateTime::from_timestamp_millis(msg.timestamp) + .map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string()) + .unwrap_or_default() + } else { + String::new() + }; + + md.push_str(&format!("### [{:03}] {} {}\n\n", i + 1, role, timestamp)); + md.push_str("```\n"); + + if let Some(ref tool_calls) = msg.tool_calls { + md.push_str(&format!("[Tool Calls]\n")); + for tc in tool_calls { + md.push_str(&format!("- {}: {:?}\n", tc.name, tc.arguments)); + } + } + + if let Some(ref tool_name) = msg.tool_name { + md.push_str(&format!("[Tool: {}]\n", tool_name)); + } + + if let Some(ref tool_call_id) = msg.tool_call_id { + md.push_str(&format!("[Tool Call ID: {}]\n", tool_call_id)); + } + + md.push_str(&msg.content); + md.push_str("\n```\n\n"); + + if !msg.media_refs.is_empty() { + md.push_str(&format!("**Media**: {:?}\n\n", msg.media_refs)); + } + } + + md + } } /// SessionManager 管理所有 Session,按 channel_name 路由 @@ -219,6 +284,11 @@ pub static SLASH_COMMANDS: &[SlashCommand] = &[ description: "Print current session information", aliases: &["/info"], }, + SlashCommand { + name: "dump", + description: "Save current session as markdown document", + aliases: &["/dump"], + }, ]; impl SessionManager { @@ -313,6 +383,16 @@ impl SessionManager { Ok((None, "No active session.".to_string())) } } + "dump" => { + if let Some(sid) = current_session_id { + let session = self.get_or_create_session(sid).await?; + let session_guard = session.lock().await; + let md = session_guard.dump_as_markdown(); + Ok((None, md)) + } else { + Ok((None, "No active session.".to_string())) + } + } _ => Err(AgentError::Other(format!("Command not implemented: {}", cmd.name))), } }