use std::collections::HashMap;
use std::time::Duration;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::{AgentPid, RegistryError, RegistryResult, SupervisorId};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct AgentRole {
pub role_id: String,
pub name: String,
pub description: String,
pub hierarchy_level: u32,
pub parent_roles: Vec<String>,
pub child_roles: Vec<String>,
pub permissions: Vec<String>,
pub knowledge_domains: Vec<String>,
}
impl AgentRole {
pub fn new(role_id: String, name: String, description: String) -> Self {
Self {
role_id,
name,
description,
hierarchy_level: 0,
parent_roles: Vec::new(),
child_roles: Vec::new(),
permissions: Vec::new(),
knowledge_domains: Vec::new(),
}
}
pub fn can_delegate_to(&self, other_role: &str) -> bool {
self.child_roles.contains(&other_role.to_string())
}
pub fn inherits_from(&self, parent_role: &str) -> bool {
self.parent_roles.contains(&parent_role.to_string())
}
pub fn has_permission(&self, permission: &str) -> bool {
self.permissions.contains(&permission.to_string())
}
pub fn specializes_in_domain(&self, domain: &str) -> bool {
self.knowledge_domains.contains(&domain.to_string())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AgentCapability {
pub capability_id: String,
pub name: String,
pub description: String,
pub category: String,
pub required_domains: Vec<String>,
pub input_types: Vec<String>,
pub output_types: Vec<String>,
pub performance_metrics: CapabilityMetrics,
pub dependencies: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilityMetrics {
pub avg_execution_time: Duration,
pub success_rate: f64,
pub resource_usage: ResourceUsage,
pub quality_score: f64,
pub last_updated: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResourceUsage {
pub memory_mb: f64,
pub cpu_percent: f64,
pub network_kbps: f64,
pub storage_mb: f64,
}
impl Default for ResourceUsage {
fn default() -> Self {
Self {
memory_mb: 0.0,
cpu_percent: 0.0,
network_kbps: 0.0,
storage_mb: 0.0,
}
}
}
impl Default for CapabilityMetrics {
fn default() -> Self {
Self {
avg_execution_time: Duration::from_secs(1),
success_rate: 1.0,
resource_usage: ResourceUsage::default(),
quality_score: 1.0,
last_updated: Utc::now(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentMetadata {
pub agent_id: AgentPid,
pub supervisor_id: SupervisorId,
pub primary_role: AgentRole,
pub secondary_roles: Vec<AgentRole>,
pub capabilities: Vec<AgentCapability>,
pub status: AgentStatus,
pub lifecycle: AgentLifecycle,
pub knowledge_context: KnowledgeContext,
pub statistics: AgentStatistics,
pub custom_fields: HashMap<String, serde_json::Value>,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AgentStatus {
Initializing,
Active,
Busy,
Idle,
Hibernating,
Terminating,
Terminated,
Failed(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentLifecycle {
pub created_at: DateTime<Utc>,
pub started_at: Option<DateTime<Utc>>,
pub stopped_at: Option<DateTime<Utc>>,
pub total_uptime: Duration,
pub restart_count: u32,
pub last_health_check: DateTime<Utc>,
pub version: String,
}
impl Default for AgentLifecycle {
fn default() -> Self {
Self {
created_at: Utc::now(),
started_at: None,
stopped_at: None,
total_uptime: Duration::ZERO,
restart_count: 0,
last_health_check: Utc::now(),
version: "1.0.0".to_string(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct KnowledgeContext {
pub domains: Vec<String>,
pub concepts: Vec<String>,
pub relationships: Vec<String>,
pub extraction_patterns: Vec<String>,
pub similarity_thresholds: HashMap<String, f64>,
pub keywords: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentStatistics {
pub tasks_completed: u64,
pub tasks_failed: u64,
pub avg_completion_time: Duration,
pub messages_processed: u64,
pub kg_queries: u64,
pub role_transitions: u64,
pub resource_history: Vec<(DateTime<Utc>, ResourceUsage)>,
pub performance_trends: HashMap<String, Vec<f64>>,
}
impl Default for AgentStatistics {
fn default() -> Self {
Self {
tasks_completed: 0,
tasks_failed: 0,
avg_completion_time: Duration::ZERO,
messages_processed: 0,
kg_queries: 0,
role_transitions: 0,
resource_history: Vec::new(),
performance_trends: HashMap::new(),
}
}
}
impl AgentMetadata {
pub fn new(agent_id: AgentPid, supervisor_id: SupervisorId, primary_role: AgentRole) -> Self {
Self {
agent_id,
supervisor_id,
primary_role,
secondary_roles: Vec::new(),
capabilities: Vec::new(),
status: AgentStatus::Initializing,
lifecycle: AgentLifecycle::default(),
knowledge_context: KnowledgeContext::default(),
statistics: AgentStatistics::default(),
custom_fields: HashMap::new(),
tags: Vec::new(),
}
}
pub fn add_secondary_role(&mut self, role: AgentRole) -> RegistryResult<()> {
if self
.secondary_roles
.iter()
.any(|r| r.role_id == role.role_id)
{
return Err(RegistryError::System(format!(
"Role {} already exists",
role.role_id
)));
}
self.secondary_roles.push(role);
Ok(())
}
pub fn remove_secondary_role(&mut self, role_id: &str) -> RegistryResult<()> {
let initial_len = self.secondary_roles.len();
self.secondary_roles.retain(|r| r.role_id != role_id);
if self.secondary_roles.len() == initial_len {
return Err(RegistryError::System(format!("Role {} not found", role_id)));
}
Ok(())
}
pub fn has_role(&self, role_id: &str) -> bool {
self.primary_role.role_id == role_id
|| self.secondary_roles.iter().any(|r| r.role_id == role_id)
}
pub fn get_all_roles(&self) -> Vec<&AgentRole> {
let mut roles = vec![&self.primary_role];
roles.extend(self.secondary_roles.iter());
roles
}
pub fn add_capability(&mut self, capability: AgentCapability) -> RegistryResult<()> {
if self
.capabilities
.iter()
.any(|c| c.capability_id == capability.capability_id)
{
return Err(RegistryError::System(format!(
"Capability {} already exists",
capability.capability_id
)));
}
self.capabilities.push(capability);
Ok(())
}
pub fn has_capability(&self, capability_id: &str) -> bool {
self.capabilities
.iter()
.any(|c| c.capability_id == capability_id)
}
pub fn get_capabilities_by_category(&self, category: &str) -> Vec<&AgentCapability> {
self.capabilities
.iter()
.filter(|c| c.category == category)
.collect()
}
pub fn update_status(&mut self, status: AgentStatus) {
self.status = status;
self.lifecycle.last_health_check = Utc::now();
}
pub fn record_task_completion(&mut self, completion_time: Duration, success: bool) {
if success {
self.statistics.tasks_completed += 1;
} else {
self.statistics.tasks_failed += 1;
}
let total_tasks = self.statistics.tasks_completed + self.statistics.tasks_failed;
if total_tasks > 0 {
let total_time =
self.statistics.avg_completion_time.as_nanos() as f64 * (total_tasks - 1) as f64;
let new_avg = (total_time + completion_time.as_nanos() as f64) / total_tasks as f64;
self.statistics.avg_completion_time = Duration::from_nanos(new_avg as u64);
}
}
pub fn record_resource_usage(&mut self, usage: ResourceUsage) {
self.statistics.resource_history.push((Utc::now(), usage));
if self.statistics.resource_history.len() > 1000 {
self.statistics.resource_history.remove(0);
}
}
pub fn get_success_rate(&self) -> f64 {
let total_tasks = self.statistics.tasks_completed + self.statistics.tasks_failed;
if total_tasks == 0 {
1.0
} else {
self.statistics.tasks_completed as f64 / total_tasks as f64
}
}
pub fn get_experience_level(&self) -> f64 {
let base_experience = (self.statistics.tasks_completed as f64 * 0.1).min(1.0);
let success_modifier = self.get_success_rate();
(base_experience * success_modifier).max(0.1) }
pub fn can_handle_domain(&self, domain: &str) -> bool {
self.get_all_roles().iter().any(|role| role.specializes_in_domain(domain)) ||
self.knowledge_context.domains.contains(&domain.to_string())
}
pub fn validate(&self) -> RegistryResult<()> {
for secondary_role in &self.secondary_roles {
if secondary_role.role_id == self.primary_role.role_id {
return Err(RegistryError::MetadataValidationFailed(
self.agent_id.clone(),
"Secondary role cannot be the same as primary role".to_string(),
));
}
}
for capability in &self.capabilities {
if capability.performance_metrics.success_rate < 0.0
|| capability.performance_metrics.success_rate > 1.0
{
return Err(RegistryError::MetadataValidationFailed(
self.agent_id.clone(),
format!(
"Invalid success rate for capability {}",
capability.capability_id
),
));
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agent_role_creation() {
let role = AgentRole::new(
"planner".to_string(),
"Planning Agent".to_string(),
"Responsible for task planning and coordination".to_string(),
);
assert_eq!(role.role_id, "planner");
assert_eq!(role.name, "Planning Agent");
assert_eq!(role.hierarchy_level, 0);
assert!(role.parent_roles.is_empty());
assert!(role.child_roles.is_empty());
}
#[test]
fn test_agent_metadata_creation() {
let agent_id = AgentPid::new();
let supervisor_id = SupervisorId::new();
let role = AgentRole::new(
"worker".to_string(),
"Worker Agent".to_string(),
"Executes assigned tasks".to_string(),
);
let metadata = AgentMetadata::new(agent_id.clone(), supervisor_id.clone(), role.clone());
assert_eq!(metadata.agent_id, agent_id);
assert_eq!(metadata.supervisor_id, supervisor_id);
assert_eq!(metadata.primary_role, role);
assert!(metadata.secondary_roles.is_empty());
assert!(metadata.capabilities.is_empty());
assert_eq!(metadata.status, AgentStatus::Initializing);
}
#[test]
fn test_role_management() {
let agent_id = AgentPid::new();
let supervisor_id = SupervisorId::new();
let primary_role = AgentRole::new(
"primary".to_string(),
"Primary Role".to_string(),
"Primary role description".to_string(),
);
let mut metadata = AgentMetadata::new(agent_id, supervisor_id, primary_role);
let secondary_role = AgentRole::new(
"secondary".to_string(),
"Secondary Role".to_string(),
"Secondary role description".to_string(),
);
metadata.add_secondary_role(secondary_role.clone()).unwrap();
assert!(metadata.has_role("secondary"));
assert_eq!(metadata.get_all_roles().len(), 2);
metadata.remove_secondary_role("secondary").unwrap();
assert!(!metadata.has_role("secondary"));
assert_eq!(metadata.get_all_roles().len(), 1);
}
#[test]
fn test_capability_management() {
let agent_id = AgentPid::new();
let supervisor_id = SupervisorId::new();
let role = AgentRole::new(
"test".to_string(),
"Test Role".to_string(),
"Test role".to_string(),
);
let mut metadata = AgentMetadata::new(agent_id, supervisor_id, role);
let capability = AgentCapability {
capability_id: "test_capability".to_string(),
name: "Test Capability".to_string(),
description: "A test capability".to_string(),
category: "testing".to_string(),
required_domains: vec!["test_domain".to_string()],
input_types: vec!["text".to_string()],
output_types: vec!["result".to_string()],
performance_metrics: CapabilityMetrics::default(),
dependencies: Vec::new(),
};
metadata.add_capability(capability).unwrap();
assert!(metadata.has_capability("test_capability"));
let test_capabilities = metadata.get_capabilities_by_category("testing");
assert_eq!(test_capabilities.len(), 1);
}
#[test]
fn test_statistics_tracking() {
let agent_id = AgentPid::new();
let supervisor_id = SupervisorId::new();
let role = AgentRole::new(
"test".to_string(),
"Test Role".to_string(),
"Test role".to_string(),
);
let mut metadata = AgentMetadata::new(agent_id, supervisor_id, role);
metadata.record_task_completion(Duration::from_secs(1), true);
assert_eq!(metadata.statistics.tasks_completed, 1);
assert_eq!(metadata.statistics.tasks_failed, 0);
assert_eq!(metadata.get_success_rate(), 1.0);
metadata.record_task_completion(Duration::from_secs(2), false);
assert_eq!(metadata.statistics.tasks_completed, 1);
assert_eq!(metadata.statistics.tasks_failed, 1);
assert_eq!(metadata.get_success_rate(), 0.5);
}
#[test]
fn test_metadata_validation() {
let agent_id = AgentPid::new();
let supervisor_id = SupervisorId::new();
let role = AgentRole::new(
"test".to_string(),
"Test Role".to_string(),
"Test role".to_string(),
);
let metadata = AgentMetadata::new(agent_id, supervisor_id, role);
assert!(metadata.validate().is_ok());
}
}