feat(TASK-049): harden hook dispatch against NUL env values and nested-supervisor latch misses
- strip interior NUL bytes from hook env values in fire_resolved so agent-authored text (e.g. escalation questions) cannot suppress a hook via a failed spawn; raise the spawn-failure log to warn! - make Supervisor::has_active_tasks recurse into child supervisors, mirroring cancel_recursive, so a prompt ctrl-c that cancels only a grandchild still latches as an interruption - document the signal-first vs error-first classification asymmetry at top_level_agent_finished / SpawnResultHooks::fire and the deliberate REPL teardown cancel; pin ctrlc-with-no-error => agent.interrupted - probe Scenario J: pty-driven ctrl-c during a live headless --agent run fires exactly one agent.interrupted with no COYOTE_AGENT_ERROR
This commit is contained in:
6 files changed
+305
-9
No files matched your search
@@ -1029,7 +1029,10 @@ impl SpawnResultHooks {
|
||||
/// Fires `agent.completed`, or — for a failed child — `agent.interrupted`
|
||||
/// when its abort signal was ctrl-c'd (REPL ctrl-c or `agent__cancel`),
|
||||
/// else `agent.failed`. The signal, never the error text, decides:
|
||||
/// cancellation is not a failure, so no error env rides along.
|
||||
/// cancellation is not a failure, so no error env rides along. Unlike the
|
||||
/// signal-first `top_level_agent_finished` gate, completion wins over a
|
||||
/// latched ctrl-c at this seam — a finished child's output is collectible,
|
||||
/// so the asymmetry is intentional.
|
||||
fn fire(self, error: Option<&str>, child_abort: &AbortSignal) {
|
||||
let mut extras = vec![
|
||||
("COYOTE_AGENT_ID", self.agent_id),
|
||||
|
||||
Reference in new issue
Block a user