use crate::context::ContextPacket;
use crate::evolution::{Genome, LlmParams};
use crate::merkle::Hash;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
pub type AgentId = Uuid;
pub type AgentHandle = Arc<RwLock<Agent>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentConfig {
pub name: String,
pub role: String,
pub max_depth: u8,
pub spawn_shadow: bool,
}
impl Default for AgentConfig {
fn default() -> Self {
Self {
name: "Agent".to_string(),
role: "General purpose assistant".to_string(),
max_depth: 3,
spawn_shadow: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Agent {
pub id: AgentId,
pub config: AgentConfig,
pub generation: u32,
pub depth: u8,
pub context: ContextPacket,
pub merkle_root: Option<Hash>,
pub created_at: DateTime<Utc>,
#[serde(skip)]
pub children: Vec<AgentId>,
#[serde(skip)]
pub shadow_id: Option<AgentId>,
pub parent_id: Option<AgentId>,
pub fitness: f64,
pub genome: Genome,
}
impl Agent {
pub fn new(config: AgentConfig) -> Self {
let genome = Genome::new(&config.role);
Self {
id: Uuid::new_v4(),
config,
generation: 0,
depth: 0,
context: ContextPacket::new(""),
merkle_root: None,
created_at: Utc::now(),
children: Vec::new(),
shadow_id: None,
parent_id: None,
fitness: 0.0,
genome,
}
}
pub fn spawn_child(&self, config: AgentConfig) -> Self {
let mut child_genome = self.genome.clone();
child_genome.prompt = config.role.clone();
Self {
id: Uuid::new_v4(),
config,
generation: self.generation + 1,
depth: self.depth + 1,
context: ContextPacket::new(""),
merkle_root: None,
created_at: Utc::now(),
children: Vec::new(),
shadow_id: None,
parent_id: Some(self.id),
fitness: 0.0,
genome: child_genome,
}
}
pub fn can_spawn(&self) -> bool {
self.depth < self.config.max_depth
}
pub fn is_root(&self) -> bool {
self.parent_id.is_none()
}
pub fn llm_params(&self) -> LlmParams {
self.genome.to_llm_params()
}
pub fn apply_evolved_genome(&mut self, evolved: Genome) {
self.genome = evolved;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_agent() {
let agent = Agent::new(AgentConfig::default());
assert!(agent.is_root());
assert_eq!(agent.generation, 0);
assert_eq!(agent.depth, 0);
}
#[test]
fn test_spawn_child() {
let parent = Agent::new(AgentConfig::default());
let child = parent.spawn_child(AgentConfig::default());
assert!(!child.is_root());
assert_eq!(child.generation, 1);
assert_eq!(child.depth, 1);
assert_eq!(child.parent_id, Some(parent.id));
}
}