2
0

feat(headless): add --once flag for single-cycle multi-agent execution

This commit is contained in:
2026-03-24 14:45:45 +09:00
parent 0044a3b059
commit 2068619afc

View File

@@ -12,6 +12,9 @@ pub fn run(config_or_task: &str, cwd_override: Option<&str>, name_override: Opti
let _ = std::fs::remove_dir_all(STATE_DIR);
create_state_dir();
let args: Vec<String> = std::env::args().collect();
let once = args.iter().any(|a| a == "--once");
let is_multi = config_or_task.ends_with(".json") || std::path::Path::new(config_or_task).is_dir();
let (configs, interval) = if is_multi {
let loaded = config::load_full(config_or_task);
@@ -34,6 +37,42 @@ pub fn run(config_or_task: &str, cwd_override: Option<&str>, name_override: Opti
return run_once(&configs);
}
// --once: run multi-agent once with AI integration, no loop
if once {
let running = Arc::new(AtomicBool::new(true));
setup_ctrlc(running.clone());
let agents = spawn_and_wait(&configs, &running);
if agents.is_empty() { return Ok(()); }
write_state(&agents);
if agents.len() > 1 {
eprintln!("\n ◐ AI integrating...");
match integrate_results(&agents, "", 1) {
Ok(d) => {
let data = serde_json::json!({
"cycle": 1,
"agents": agents.iter().map(|a| a.to_ai_json()).collect::<Vec<_>>(),
"decision": &d,
});
atomic_write(
&format!("{STATE_DIR}/decision.json"),
serde_json::to_string_pretty(&data).unwrap_or_default().as_bytes(),
);
eprintln!(" ✓ Done\n");
println!("{d}");
}
Err(e) => eprintln!("{e}"),
}
} else {
println!("{}", strip_dir_listing(&agents[0].output));
}
let all: Vec<usize> = (0..agents.len()).collect();
let path = save_session(1, &agents, "", &all);
eprintln!(" saved: {path}");
return Ok(());
}
let running = Arc::new(AtomicBool::new(true));
setup_ctrlc(running.clone());
@@ -142,8 +181,50 @@ pub fn run(config_or_task: &str, cwd_override: Option<&str>, name_override: Opti
pub fn run_preset(preset_name: &str) -> Result<(), String> {
let configs = config::preset(preset_name)
.ok_or_else(|| format!("unknown preset: {preset_name}"))?;
let once = std::env::args().any(|a| a == "--once");
if once {
run_once_multi(configs)
} else {
run_with_configs(configs)
}
}
fn run_once_multi(configs: Vec<config::AgentConfig>) -> Result<(), String> {
let _ = std::fs::remove_dir_all(STATE_DIR);
create_state_dir();
let running = Arc::new(AtomicBool::new(true));
setup_ctrlc(running.clone());
let agents = spawn_and_wait(&configs, &running);
if agents.is_empty() { return Ok(()); }
write_state(&agents);
if agents.len() > 1 {
eprintln!("\n ◐ AI integrating...");
match integrate_results(&agents, "", 1) {
Ok(d) => {
let data = serde_json::json!({
"cycle": 1,
"agents": agents.iter().map(|a| a.to_ai_json()).collect::<Vec<_>>(),
"decision": &d,
});
atomic_write(
&format!("{STATE_DIR}/decision.json"),
serde_json::to_string_pretty(&data).unwrap_or_default().as_bytes(),
);
eprintln!(" ✓ Done\n");
println!("{d}");
}
Err(e) => eprintln!("{e}"),
}
} else {
println!("{}", strip_dir_listing(&agents[0].output));
}
let all: Vec<usize> = (0..agents.len()).collect();
let path = save_session(1, &agents, "", &all);
eprintln!(" saved: {path}");
Ok(())
}
fn run_with_configs(configs: Vec<config::AgentConfig>) -> Result<(), String> {
let _ = std::fs::remove_dir_all(STATE_DIR);