hook: log gate decision and agent spawn outcomes
The old hook was silent about why it did or didn't launch an agent — when nothing fired, it was impossible to tell whether the event was gated out, a pending chunk was served, or spawn_agent silently returned None. Logs now cover each of those cases: hook_event=... surface_hooks=[...] gated_in=true/false serving pending chunk (N bytes); skipping agent cycles surface-observe: spawned pid 501605 (log: ...) surface-observe: spawn_agent returned None surface-observe: skipped — pid 501605 in phase "surface" Rename surface_phase_busy to surface_phase_blocker and have it return the pid + phase that's blocking, so stale-pid scenarios are diagnosable from the log instead of needing a live ps walk. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
719d3a4856
commit
199ce0ecdc
3 changed files with 221 additions and 30 deletions
|
|
@ -259,16 +259,24 @@ impl AgentCycleState {
|
|||
// to start while an older agent finishes out its post-surface
|
||||
// phases is the whole point — surface can run at a higher cadence
|
||||
// than the full organize/observe tail.
|
||||
if surface_phase_busy(&state_dir) {
|
||||
self.log(format_args!("surface-observe already in surface phase\n"));
|
||||
if let Some((blocking_pid, phase)) = surface_phase_blocker(&state_dir) {
|
||||
self.log(format_args!(
|
||||
"surface-observe: skipped — pid {} in phase {:?}\n", blocking_pid, phase));
|
||||
} else {
|
||||
if transcript.size > 0 {
|
||||
fs::write(&offset_path, transcript.size.to_string()).ok();
|
||||
}
|
||||
if let Some(result) = consciousness::agent::oneshot::spawn_agent(
|
||||
match consciousness::agent::oneshot::spawn_agent(
|
||||
"surface-observe", &state_dir, &session.session_id) {
|
||||
self.log(format_args!("spawned surface-observe pid {}\n", result.child.id()));
|
||||
self.agent_spawned("surface-observe", "surface", result);
|
||||
Some(result) => {
|
||||
self.log(format_args!(
|
||||
"surface-observe: spawned pid {} (log: {})\n",
|
||||
result.child.id(), result.log_path.display()));
|
||||
self.agent_spawned("surface-observe", "surface", result);
|
||||
}
|
||||
None => {
|
||||
self.log(format_args!("surface-observe: spawn_agent returned None\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,10 +317,14 @@ impl AgentCycleState {
|
|||
}
|
||||
|
||||
fs::write(&offset_path, transcript.size.to_string()).ok();
|
||||
if let Some(result) = consciousness::agent::oneshot::spawn_agent(
|
||||
match consciousness::agent::oneshot::spawn_agent(
|
||||
"reflect", &state_dir, &session.session_id) {
|
||||
self.log(format_args!("reflect: spawned pid {}\n", result.child.id()));
|
||||
self.agent_spawned("reflect", "step-0", result);
|
||||
Some(result) => {
|
||||
self.log(format_args!("reflect: spawned pid {} (log: {})\n",
|
||||
result.child.id(), result.log_path.display()));
|
||||
self.agent_spawned("reflect", "step-0", result);
|
||||
}
|
||||
None => self.log(format_args!("reflect: spawn_agent returned None\n")),
|
||||
}
|
||||
|
||||
reflection
|
||||
|
|
@ -338,33 +350,38 @@ impl AgentCycleState {
|
|||
}
|
||||
|
||||
fs::write(&offset_path, transcript.size.to_string()).ok();
|
||||
if let Some(result) = consciousness::agent::oneshot::spawn_agent(
|
||||
match consciousness::agent::oneshot::spawn_agent(
|
||||
"journal", &state_dir, &session.session_id) {
|
||||
self.log(format_args!("journal: spawned pid {}\n", result.child.id()));
|
||||
self.agent_spawned("journal", "step-0", result);
|
||||
Some(result) => {
|
||||
self.log(format_args!("journal: spawned pid {} (log: {})\n",
|
||||
result.child.id(), result.log_path.display()));
|
||||
self.agent_spawned("journal", "step-0", result);
|
||||
}
|
||||
None => self.log(format_args!("journal: spawn_agent returned None\n")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Is there a live agent in `state_dir` currently in the "surface" phase?
|
||||
/// Inspects pid-<N> files; their content is the phase string, kept fresh
|
||||
/// by bail-no-competing.sh on each step transition.
|
||||
fn surface_phase_busy(state_dir: &Path) -> bool {
|
||||
let Ok(entries) = fs::read_dir(state_dir) else { return false; };
|
||||
/// If a live agent in `state_dir` is currently in the "surface" phase,
|
||||
/// return its pid + phase string. Inspects pid-<N> files; their content
|
||||
/// is the phase string, kept fresh by bail-no-competing.sh on each step
|
||||
/// transition. Stale pid files (process already dead) are ignored.
|
||||
fn surface_phase_blocker(state_dir: &Path) -> Option<(i32, String)> {
|
||||
let entries = fs::read_dir(state_dir).ok()?;
|
||||
for entry in entries.flatten() {
|
||||
let fname = entry.file_name();
|
||||
let fname_s = fname.to_string_lossy();
|
||||
let Some(pid_str) = fname_s.strip_prefix("pid-") else { continue; };
|
||||
let Ok(pid) = pid_str.parse::<i32>() else { continue; };
|
||||
// Is the process alive?
|
||||
let alive = unsafe { libc::kill(pid, 0) } == 0;
|
||||
if !alive { continue; }
|
||||
let phase = fs::read_to_string(entry.path()).unwrap_or_default();
|
||||
if phase.trim() == "surface" {
|
||||
return true;
|
||||
let phase = phase.trim().to_string();
|
||||
if phase == "surface" {
|
||||
return Some((pid, phase));
|
||||
}
|
||||
}
|
||||
false
|
||||
None
|
||||
}
|
||||
|
||||
/// Format agent cycle output for injection into a Claude Code session.
|
||||
|
|
|
|||
|
|
@ -188,10 +188,14 @@ fn hook(session: &HookSession) -> String {
|
|||
}
|
||||
|
||||
if let Some(chunk) = pop_pending_chunk(&session.state_dir, &session.session_id) {
|
||||
let _ = writeln!(log_f, "serving pending chunk ({} bytes); skipping agent cycles", chunk.len());
|
||||
out.push_str(&chunk);
|
||||
} else {
|
||||
let cfg = consciousness::config::get();
|
||||
if cfg.surface_hooks.iter().any(|h| h == &session.hook_event) {
|
||||
let gated_in = cfg.surface_hooks.iter().any(|h| h == &session.hook_event);
|
||||
let _ = writeln!(log_f, "hook_event={} surface_hooks={:?} gated_in={}",
|
||||
session.hook_event, cfg.surface_hooks, gated_in);
|
||||
if gated_in {
|
||||
let cycle_output = run_agent_cycles(&session);
|
||||
out.push_str(&format_agent_output(&cycle_output));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue