Use own state for spawn decisions, not pid file scanning
AgentCycleState tracks its own children — agent_running() checks child handles instead of scan_pid_files(). poll_children() reaps completed processes. No filesystem scanning for agent lifecycle. The Claude Code hook path will need serialized AgentCycleState to persist across invocations (next step). Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
9ac50bd999
commit
90d2717423
1 changed files with 15 additions and 24 deletions
|
|
@ -206,6 +206,10 @@ impl AgentCycleState {
|
|||
}
|
||||
}
|
||||
|
||||
fn agent_running(&self, name: &str) -> bool {
|
||||
self.agents.iter().any(|a| a.name == name && a.child.is_some())
|
||||
}
|
||||
|
||||
fn agent_spawned(&mut self, name: &str, phase: &str,
|
||||
result: crate::agents::knowledge::SpawnResult) {
|
||||
if let Some(agent) = self.agents.iter_mut().find(|a| a.name == name) {
|
||||
|
|
@ -306,15 +310,6 @@ impl AgentCycleState {
|
|||
.and_then(|s| s.trim().parse().ok())
|
||||
.unwrap_or(0);
|
||||
|
||||
let timeout = crate::config::get()
|
||||
.surface_timeout_secs
|
||||
.unwrap_or(300) as u64;
|
||||
|
||||
let live = crate::agents::knowledge::scan_pid_files(&state_dir, timeout);
|
||||
for (phase, pid) in &live {
|
||||
self.log(format_args!("alive pid-{}: phase={}\n", pid, phase));
|
||||
}
|
||||
|
||||
// Read surfaced keys
|
||||
let mut surfaced_keys = Vec::new();
|
||||
let surface_path = state_dir.join("surface");
|
||||
|
|
@ -337,12 +332,10 @@ impl AgentCycleState {
|
|||
fs::remove_file(&surface_path).ok();
|
||||
}
|
||||
|
||||
// Spawn new agent if needed
|
||||
let live = crate::agents::knowledge::scan_pid_files(&state_dir, timeout);
|
||||
let any_in_surface = live.iter().any(|(p, _)| p == "surface");
|
||||
|
||||
if any_in_surface {
|
||||
self.log(format_args!("agent in surface phase, waiting\n"));
|
||||
// Spawn new agent if not already running
|
||||
let running = self.agent_running("surface-observe");
|
||||
if running {
|
||||
self.log(format_args!("surface-observe already running\n"));
|
||||
} else {
|
||||
if transcript.size > 0 {
|
||||
fs::write(&offset_path, transcript.size.to_string()).ok();
|
||||
|
|
@ -358,7 +351,7 @@ impl AgentCycleState {
|
|||
let mut sleep_secs = None;
|
||||
let conversation_budget: u64 = 50_000;
|
||||
|
||||
if !live.is_empty() && transcript.size > 0 {
|
||||
if running && transcript.size > 0 {
|
||||
let behind = transcript.size.saturating_sub(last_offset);
|
||||
|
||||
if behind > conversation_budget / 2 {
|
||||
|
|
@ -367,8 +360,8 @@ impl AgentCycleState {
|
|||
|
||||
for _ in 0..5 {
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
let still_live = crate::agents::knowledge::scan_pid_files(&state_dir, timeout);
|
||||
if still_live.is_empty() { break; }
|
||||
self.poll_children();
|
||||
if !self.agent_running("surface-observe") { break; }
|
||||
}
|
||||
|
||||
let secs = (Instant::now() - sleep_start).as_secs_f64();
|
||||
|
|
@ -394,9 +387,8 @@ impl AgentCycleState {
|
|||
return None;
|
||||
}
|
||||
|
||||
let live = crate::agents::knowledge::scan_pid_files(&state_dir, 300);
|
||||
if let Some((phase, pid)) = live.first() {
|
||||
self.log(format_args!("reflect: already running pid {}\n", pid));
|
||||
if self.agent_running("reflect") {
|
||||
self.log(format_args!("reflect: already running\n"));
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -438,9 +430,8 @@ impl AgentCycleState {
|
|||
return;
|
||||
}
|
||||
|
||||
let live = crate::agents::knowledge::scan_pid_files(&state_dir, 300);
|
||||
if let Some((phase, pid)) = live.first() {
|
||||
self.log(format_args!("journal: already running pid {}\n", pid));
|
||||
if self.agent_running("journal") {
|
||||
self.log(format_args!("journal: already running\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue