use std::path::{Path, PathBuf};
use anyhow::Result;
use tokio_util::sync::CancellationToken;
use crate::api::provider::OpenAiCompatibleProvider;
use crate::config::Config;
use crate::evolution::{
adapter::ColletEvolvable, benchmarks::NullBenchmark, config::EvolveConfig,
engines::SkillforgeEngine, r#loop::EvolutionLoop, trial::TrialRunner,
};
pub const GLOBAL_AGENT: &str = "collet";
pub fn workspace_path(collet_home: &Path, agent_name: &str) -> PathBuf {
if agent_name == GLOBAL_AGENT {
collet_home.join("workspace")
} else {
collet_home
.join("agents")
.join(agent_name)
.join("workspace")
}
}
pub fn is_auto_enabled(config: &Config) -> bool {
config.evolution_enabled
}
pub async fn run_auto(
client: OpenAiCompatibleProvider,
config: Config,
collet_home: PathBuf,
agent_name: String,
working_dir: String,
cancel: CancellationToken,
) -> Result<()> {
let workspace_root = workspace_path(&collet_home, &agent_name);
std::fs::create_dir_all(&workspace_root)?;
let cycles = config.evolution_cycles;
let evolver_model = config
.evolution_model
.clone()
.unwrap_or_else(|| config.model.clone());
let evolve_config = EvolveConfig {
max_cycles: cycles,
batch_size: 1,
evolver_model,
..Default::default()
};
let evolvable = ColletEvolvable::new(
client.clone(),
config.clone(),
workspace_root.clone(),
working_dir,
);
let benchmark = Box::new(NullBenchmark);
let trial = TrialRunner::new(Box::new(evolvable), benchmark);
let (evo_tx, _evo_rx) = tokio::sync::mpsc::unbounded_channel();
let mut evo_loop = EvolutionLoop::new(workspace_root, trial, evolve_config.clone(), evo_tx)?;
let evolver_client = if evolve_config.evolver_model != config.model {
crate::api::provider::OpenAiCompatibleProvider::new(
client.base_url().to_string(),
client.api_key().to_string(),
evolve_config.evolver_model.clone(),
config.context_max_tokens,
)
.unwrap_or_else(|_| client.clone())
} else {
client
};
let mut engine = SkillforgeEngine::new(evolve_config, evolver_client);
evo_loop.run(&mut engine, cancel).await?;
Ok(())
}