use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum CollaborationMode {
#[default]
RequestResponse,
PublishSubscribe,
Consensus,
Debate,
Parallel,
Sequential,
Custom(String),
}
impl std::fmt::Display for CollaborationMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CollaborationMode::RequestResponse => write!(f, "请求-响应模式"),
CollaborationMode::PublishSubscribe => write!(f, "发布-订阅模式"),
CollaborationMode::Consensus => write!(f, "共识机制模式"),
CollaborationMode::Debate => write!(f, "辩论模式"),
CollaborationMode::Parallel => write!(f, "并行处理模式"),
CollaborationMode::Sequential => write!(f, "顺序执行模式"),
CollaborationMode::Custom(s) => write!(f, "{}", s),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CollaborationMessage {
pub id: String,
pub sender: String,
pub receiver: Option<String>,
pub topic: Option<String>,
pub content: CollaborationContent,
pub mode: CollaborationMode,
pub timestamp: u64,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CollaborationContent {
Text(String),
Data(serde_json::Value),
Mixed {
text: String,
data: serde_json::Value,
},
LLMResponse {
reasoning: String, conclusion: String, data: serde_json::Value, },
}
impl CollaborationContent {
pub fn to_text(&self) -> String {
match self {
CollaborationContent::Text(s) => s.clone(),
CollaborationContent::Data(v) => v.to_string(),
CollaborationContent::Mixed { text, data } => format!("{}\n\n数据: {}", text, data),
CollaborationContent::LLMResponse {
reasoning,
conclusion,
..
} => {
format!("推理: {}\n\n结论: {}", reasoning, conclusion)
}
}
}
}
impl From<String> for CollaborationContent {
fn from(s: String) -> Self {
CollaborationContent::Text(s)
}
}
impl From<&str> for CollaborationContent {
fn from(s: &str) -> Self {
CollaborationContent::Text(s.to_string())
}
}
impl From<serde_json::Value> for CollaborationContent {
fn from(v: serde_json::Value) -> Self {
CollaborationContent::Data(v)
}
}
impl CollaborationMessage {
pub fn new(
sender: String,
content: impl Into<CollaborationContent>,
mode: CollaborationMode,
) -> Self {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
Self {
id: Uuid::now_v7().to_string(),
sender,
receiver: None,
topic: None,
content: content.into(),
mode,
timestamp: now,
metadata: HashMap::new(),
}
}
pub fn with_receiver(mut self, receiver: String) -> Self {
self.receiver = Some(receiver);
self
}
pub fn with_topic(mut self, topic: String) -> Self {
self.topic = Some(topic);
self
}
pub fn with_metadata(mut self, key: String, value: String) -> Self {
self.metadata.insert(key, value);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CollaborationResult {
pub success: bool,
pub data: Option<CollaborationContent>,
pub error: Option<String>,
pub duration_ms: u64,
pub participants: Vec<String>,
pub mode: CollaborationMode,
pub decision_context: Option<DecisionContext>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DecisionContext {
pub reasoning: String,
pub task_analysis: String,
pub alternatives: Vec<CollaborationMode>,
pub confidence: f32,
}
impl CollaborationResult {
pub fn success(
data: impl Into<CollaborationContent>,
duration_ms: u64,
mode: CollaborationMode,
) -> Self {
Self {
success: true,
data: Some(data.into()),
error: None,
duration_ms,
participants: Vec::new(),
mode,
decision_context: None,
}
}
pub fn success_with_llm_decision(
data: impl Into<CollaborationContent>,
duration_ms: u64,
mode: CollaborationMode,
decision: DecisionContext,
) -> Self {
Self {
success: true,
data: Some(data.into()),
error: None,
duration_ms,
participants: Vec::new(),
mode,
decision_context: Some(decision),
}
}
pub fn failure(error: String, mode: CollaborationMode) -> Self {
Self {
success: false,
data: None,
error: Some(error),
duration_ms: 0,
participants: Vec::new(),
mode,
decision_context: None,
}
}
pub fn with_participant(mut self, agent_id: String) -> Self {
self.participants.push(agent_id);
self
}
}
#[async_trait]
pub trait CollaborationProtocol: Send + Sync {
fn name(&self) -> &str;
fn version(&self) -> &str {
"1.0.0"
}
fn mode(&self) -> CollaborationMode;
fn description(&self) -> &str {
"Collaboration protocol"
}
fn applicable_scenarios(&self) -> Vec<String> {
vec![]
}
async fn send_message(&self, msg: CollaborationMessage) -> anyhow::Result<()>;
async fn receive_message(&self) -> anyhow::Result<Option<CollaborationMessage>>;
async fn process_message(
&self,
msg: CollaborationMessage,
) -> anyhow::Result<CollaborationResult>;
fn is_available(&self) -> bool {
true
}
fn stats(&self) -> HashMap<String, serde_json::Value> {
HashMap::new()
}
}
pub fn scenario_to_mode_suggestions() -> HashMap<String, Vec<CollaborationMode>> {
HashMap::from([
(
"数据处理".to_string(),
vec![
CollaborationMode::RequestResponse,
CollaborationMode::Parallel,
],
),
(
"创意生成".to_string(),
vec![
CollaborationMode::PublishSubscribe,
CollaborationMode::Debate,
],
),
(
"决策制定".to_string(),
vec![CollaborationMode::Consensus, CollaborationMode::Debate],
),
(
"分析任务".to_string(),
vec![CollaborationMode::Parallel, CollaborationMode::Sequential],
),
(
"审查任务".to_string(),
vec![CollaborationMode::Debate, CollaborationMode::Consensus],
),
(
"搜索任务".to_string(),
vec![
CollaborationMode::Parallel,
CollaborationMode::RequestResponse,
],
),
])
}
#[derive(Clone)]
pub struct ProtocolRegistry {
protocols: Arc<RwLock<HashMap<String, Arc<dyn CollaborationProtocol>>>>,
}
impl Default for ProtocolRegistry {
fn default() -> Self {
Self::new()
}
}
impl ProtocolRegistry {
pub fn new() -> Self {
Self {
protocols: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn register(&self, protocol: Arc<dyn CollaborationProtocol>) -> anyhow::Result<()> {
let name = protocol.name().to_string();
let mut protocols = self.protocols.write().await;
protocols.insert(name.clone(), protocol);
tracing::debug!("Registered collaboration protocol: {}", name);
Ok(())
}
pub async fn get(&self, name: &str) -> Option<Arc<dyn CollaborationProtocol>> {
let protocols = self.protocols.read().await;
protocols.get(name).cloned()
}
pub async fn list_all(&self) -> Vec<Arc<dyn CollaborationProtocol>> {
let protocols = self.protocols.read().await;
protocols.values().cloned().collect()
}
pub async fn list_names(&self) -> Vec<String> {
let protocols = self.protocols.read().await;
protocols.keys().cloned().collect()
}
pub async fn count(&self) -> usize {
let protocols = self.protocols.read().await;
protocols.len()
}
pub async fn get_descriptions(&self) -> HashMap<String, ProtocolDescription> {
let protocols = self.protocols.read().await;
protocols
.iter()
.map(|(name, protocol)| {
(
name.clone(),
ProtocolDescription {
name: name.clone(),
mode: protocol.mode(),
description: protocol.description().to_string(),
scenarios: protocol.applicable_scenarios(),
},
)
})
.collect()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProtocolDescription {
pub name: String,
pub mode: CollaborationMode,
pub description: String,
pub scenarios: Vec<String>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct CollaborationStats {
pub total_tasks: u64,
pub successful_tasks: u64,
pub failed_tasks: u64,
pub mode_usage: HashMap<String, u64>,
pub avg_duration_ms: f64,
pub llm_decisions: LLMDecisionStats,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct LLMDecisionStats {
pub total_decisions: u64,
pub mode_selections: HashMap<String, u64>,
pub avg_confidence: f32,
}
pub struct LLMDrivenCollaborationManager {
agent_id: String,
registry: ProtocolRegistry,
current_protocol: Arc<RwLock<Option<Arc<dyn CollaborationProtocol>>>>,
message_queue: Arc<RwLock<Vec<CollaborationMessage>>>,
stats: Arc<RwLock<CollaborationStats>>,
}
impl LLMDrivenCollaborationManager {
pub fn new(agent_id: impl Into<String>) -> Self {
let agent_id = agent_id.into();
Self {
agent_id,
registry: ProtocolRegistry::new(),
current_protocol: Arc::new(RwLock::new(None)),
message_queue: Arc::new(RwLock::new(Vec::new())),
stats: Arc::new(RwLock::new(CollaborationStats::default())),
}
}
pub fn agent_id(&self) -> &str {
&self.agent_id
}
pub fn registry(&self) -> &ProtocolRegistry {
&self.registry
}
pub async fn register_protocol(
&self,
protocol: Arc<dyn CollaborationProtocol>,
) -> anyhow::Result<()> {
self.registry.register(protocol).await
}
pub async fn execute_task_with_protocol(
&self,
protocol_name: &str,
content: impl Into<CollaborationContent>,
) -> anyhow::Result<CollaborationResult> {
let start = std::time::Instant::now();
{
let mut stats = self.stats.write().await;
stats.total_tasks += 1;
}
let protocol = self
.registry
.get(protocol_name)
.await
.ok_or_else(|| anyhow::anyhow!("Protocol not found: {}", protocol_name))?;
{
let mut current = self.current_protocol.write().await;
*current = Some(protocol.clone());
}
let msg = CollaborationMessage::new(self.agent_id.clone(), content, protocol.mode());
let result = protocol.process_message(msg).await;
let duration = start.elapsed().as_millis() as u64;
match result {
Ok(mut result) => {
result.duration_ms = duration;
{
let mut stats = self.stats.write().await;
stats.successful_tasks += 1;
let mode_key = protocol.mode().to_string();
*stats.mode_usage.entry(mode_key).or_insert(0) += 1;
let total = stats.successful_tasks + stats.failed_tasks;
if total > 0 {
stats.avg_duration_ms = (stats.avg_duration_ms * (total - 1) as f64
+ duration as f64)
/ total as f64;
}
}
Ok(result)
}
Err(e) => {
{
let mut stats = self.stats.write().await;
stats.failed_tasks += 1;
}
Ok(CollaborationResult::failure(e.to_string(), protocol.mode()))
}
}
}
pub async fn send_message(&self, msg: CollaborationMessage) -> anyhow::Result<()> {
let mut queue = self.message_queue.write().await;
queue.push(msg);
Ok(())
}
pub async fn receive_message(&self) -> anyhow::Result<Option<CollaborationMessage>> {
let mut queue = self.message_queue.write().await;
Ok(queue.pop())
}
pub async fn current_protocol(&self) -> Option<Arc<dyn CollaborationProtocol>> {
let current = self.current_protocol.read().await;
current.clone()
}
pub async fn stats(&self) -> CollaborationStats {
self.stats.read().await.clone()
}
pub async fn reset_stats(&self) {
let mut stats = self.stats.write().await;
*stats = CollaborationStats::default();
}
pub async fn get_protocol_descriptions(&self) -> HashMap<String, ProtocolDescription> {
self.registry.get_descriptions().await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_collaboration_mode_display() {
assert_eq!(
CollaborationMode::RequestResponse.to_string(),
"请求-响应模式"
);
assert_eq!(
CollaborationMode::PublishSubscribe.to_string(),
"发布-订阅模式"
);
assert_eq!(CollaborationMode::Consensus.to_string(), "共识机制模式");
}
#[test]
fn test_collaboration_message_creation() {
let msg = CollaborationMessage::new(
"agent_001".to_string(),
"Test content",
CollaborationMode::RequestResponse,
)
.with_receiver("agent_002".to_string())
.with_topic("test_topic".to_string());
assert_eq!(msg.sender, "agent_001");
assert_eq!(msg.receiver, Some("agent_002".to_string()));
assert_eq!(msg.topic, Some("test_topic".to_string()));
}
#[test]
fn test_collaboration_content() {
let text_content: CollaborationContent = "Hello".to_string().into();
assert_eq!(text_content.to_text(), "Hello");
let json_content: CollaborationContent = serde_json::json!({"key": "value"}).into();
assert!(json_content.to_text().contains("key"));
}
#[test]
fn test_protocol_registry() {
let registry = ProtocolRegistry::new();
#[tokio::test]
async fn test_empty_registry() {
let registry = ProtocolRegistry::new();
assert_eq!(registry.count().await, 0);
assert!(registry.list_names().await.is_empty());
}
}
#[tokio::test]
async fn test_llm_driven_manager() {
let manager = LLMDrivenCollaborationManager::new("test_agent");
assert_eq!(manager.agent_id(), "test_agent");
assert_eq!(manager.registry().count().await, 0);
}
#[tokio::test]
async fn test_message_queue() {
let manager = LLMDrivenCollaborationManager::new("test_agent");
let msg = CollaborationMessage::new(
"agent_001".to_string(),
"Test content",
CollaborationMode::RequestResponse,
);
manager.send_message(msg).await.unwrap();
let received = manager.receive_message().await.unwrap();
assert!(received.is_some());
assert_eq!(received.unwrap().sender, "agent_001");
}
}