// src/agent/team/inbox.rs // // 团队消息邮箱系统。 // 使用 .team/{session_id}/inbox/{agent_name}.jsonl 作为 append-only 消息文件。 use chrono::Utc; use serde::{Deserialize, Serialize}; use std::io::Write; use std::path::{Path, PathBuf}; /// 团队消息类型 #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum TeamMessageType { Task, Result, Question, Answer, Status, } impl TeamMessageType { pub fn as_str(&self) -> &str { match self { TeamMessageType::Task => "task", TeamMessageType::Result => "result", TeamMessageType::Question => "question", TeamMessageType::Answer => "answer", TeamMessageType::Status => "status", } } } /// 团队消息 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TeamMessage { pub from: String, pub to: String, pub content: String, pub msg_type: TeamMessageType, pub timestamp: String, } impl TeamMessage { pub fn new(from: &str, to: &str, content: &str, msg_type: TeamMessageType) -> Self { TeamMessage { from: from.to_string(), to: to.to_string(), content: content.to_string(), msg_type, timestamp: Utc::now().to_rfc3339(), } } } /// 获取团队目录路径 pub fn team_dir(session_id: &str) -> PathBuf { PathBuf::from(".team").join(session_id) } /// 获取指定 agent 的收件箱路径 pub fn inbox_path(team_dir: &Path, agent_name: &str) -> PathBuf { team_dir.join("inbox").join(format!("{}.jsonl", agent_name)) } /// 向收件箱追加一条消息 pub fn append_message(team_dir: &Path, agent_name: &str, msg: &TeamMessage) -> std::io::Result<()> { let inbox = inbox_path(team_dir, agent_name); if let Some(parent) = inbox.parent() { std::fs::create_dir_all(parent)?; } let line = serde_json::to_string(msg).unwrap_or_default(); let mut file = std::fs::OpenOptions::new() .create(true) .append(true) .open(&inbox)?; file.write_all(line.as_bytes())?; file.write_all(b"\n")?; Ok(()) } /// 读取并清空收件箱 pub fn drain_inbox(team_dir: &Path, agent_name: &str) -> Vec { let inbox = inbox_path(team_dir, agent_name); if !inbox.exists() { return Vec::new(); } let content = match std::fs::read_to_string(&inbox) { Ok(c) => c, Err(_) => return Vec::new(), }; let messages: Vec = content .lines() .filter(|l| !l.is_empty()) .filter_map(|l| serde_json::from_str(l).ok()) .collect(); // 清空文件 let _ = std::fs::write(&inbox, ""); messages } /// 检查收件箱中是否有未读消息 pub fn has_pending(team_dir: &Path, agent_name: &str) -> bool { let inbox = inbox_path(team_dir, agent_name); inbox.exists() && inbox.metadata().map(|m| m.len() > 0).unwrap_or(false) }