架构重构: - Agent Runtime 由单文件拆为 runtime/ 目录 12 模块(熔断/流式执行/Token预算/文件缓存/权限等) - Agent Tools 由单文件拆为 tools/ 目录 20+ 模块(filesystem/astro/memory/skill/subagent/team 等) - 解析器体系重构(common.rs 836行变更),各解析器同步升级 - Download 服务重构(562行),反爬策略强化 - LLM 客户端重构(266行),流式调用优化 新子系统: - Hooks 生命周期系统(9种事件类型,PreToolUse/PostToolUse 支持输入输出拦截) - Skills 双层加载系统(system-reminder 轻量注入 + LoadSkillTool 按需加载,notify 文件监听热更新) - Memory 项目记忆管理(类型/提取/去重/衰减/保活/选择策略/护栏 7 模块) - SubAgent 上下文隔离子代理运行器(独立 ReAct 循环 + Hook 管道) - Team 多智能体团队协作(文件 inbox 通信、lead/teammate 协调) - TaskBoard DAG 任务依赖管理 - Trajectory 会话轨迹、Terminal 终止信号、Autonomous 自主模式、Background 异步通知 数据库: - agent_tasks 表(DAG 依赖模式,blocked_by JSON 数组) - agent_audit_log 表(工具调用审计:名称/状态/耗时/输出预览) - agent_identity 迁移(消息/审计/任务的 agent_name 归属,agent_team_members 团队注册表) API: - GET /chat/metrics 聚合指标端点 - GET /chat/sessions/:id/audit 会话审计查询 - GET /chat/questions + POST /chat/answer 人机交互问答 工程: - 新增依赖:serde_yaml、notify、glob、walkdir、lru - Skills 目录含 methodology/plotting/presentation 三个初始 SKILL.md - CLAUDE.md 完整项目架构文档
111 lines
2.9 KiB
Rust
111 lines
2.9 KiB
Rust
// 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<TeamMessage> {
|
|
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<TeamMessage> = 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)
|
|
}
|