feat(supervisor): push agent completion notifications to the spawning context

The spawned-agent task now pushes an agent_completed/agent_failed event
into the spawning context's notification queue before returning, so a
parent that keeps working learns mid-turn that a child finished instead
of discovering it only at the turn-end guardrail. Cancelled or
already-collected agents are suppressed by the existing drain-time
registration filter. This delivery applies regardless of whether
background jobs are enabled.
This commit is contained in:
2026-08-25 17:52:19 -06:00
parent 2d874f1d7c
commit caabf41b65
3 changed files with 118 additions and 7 deletions
+15 -6
View File
@@ -5,6 +5,7 @@ use crate::config::{
jobs_enabled, list_agents_with_descriptions,
};
use crate::supervisor::mailbox::{Envelope, EnvelopePayload, Inbox};
use crate::supervisor::notification::agent_notification;
use crate::supervisor::{AgentExitStatus, AgentHandle, AgentResult, Supervisor, TaskKind};
use crate::utils::{AbortSignal, create_abort_signal, wait_abort_signal};
@@ -866,25 +867,33 @@ async fn handle_spawn(ctx: &mut RequestContext, args: &Value) -> Result<Value> {
let spawn_agent_id = agent_id.clone();
let spawn_agent_name = agent_name.clone();
let spawn_abort = child_abort.clone();
let spawn_notifications = Arc::clone(&ctx.notification_queue);
let child_supervisor = child_ctx.supervisor.clone();
let join_handle = tokio::spawn(async move {
let result = run_child_agent(child_ctx, input, spawn_abort).await;
match result {
Ok(output) => Ok(AgentResult {
let agent_result = match result {
Ok(output) => AgentResult {
id: spawn_agent_id,
agent_name: spawn_agent_name,
output,
exit_status: AgentExitStatus::Completed,
}),
Err(e) => Ok(AgentResult {
},
Err(e) => AgentResult {
id: spawn_agent_id,
agent_name: spawn_agent_name,
output: String::new(),
exit_status: AgentExitStatus::Failed(e.to_string()),
}),
}
},
};
let success = agent_result.exit_status == AgentExitStatus::Completed;
spawn_notifications.push(agent_notification(
&agent_result.id,
&agent_result.agent_name,
success,
));
Ok(agent_result)
});
let handle = AgentHandle {