Spawning Child Agents
Agents can spawn child agents to parallelize work or delegate subtasks. The spawning agent becomes the parent in the escalation hierarchy.
Spawning via IPC
Use the AgentdClient directly to spawn a child:
#![allow(unused)] fn main() { use libagent::ipc::{Request, Response}; use libagent::manifest::AgentManifest; // Load or construct a manifest for the child let manifest_yaml = std::fs::read_to_string("worker-agent.yaml")?; let manifest: AgentManifest = serde_yaml::from_str(&manifest_yaml)?; // Spawn the child let response = agent.client.send(Request::SpawnAgent { manifest, parent_id: Some(agent.id), // sets this agent as parent in hierarchy }).await?; let child_id = match response { Response::AgentSpawned { agent_id, .. } => agent_id, Response::Error { message } => return Err(message.into()), _ => return Err("unexpected response".into()), }; tracing::info!("Spawned child agent {}", child_id); }
Monitoring Child Agents
Check child agent status by querying the daemon:
#![allow(unused)] fn main() { let response = agent.client.send(Request::GetAgentInfo { agent_id: child_id, }).await?; }
Or watch for escalations from the child:
#![allow(unused)] fn main() { let escalations = agent.pending_escalations().await?; for esc in escalations { if esc["agent_id"] == child_id.to_string() { // Child sent an escalation } } }
Coordinating with Children via Bus
Publish tasks to children and receive results:
#![allow(unused)] fn main() { // Parent publishes a task agent.client.bus_publish(agent.id, "tasks.new", json!({ "task": "analyze dataset chunk 3", "output_key": "results.chunk-3" })).await?; // Child (in child's code) subscribes and polls: // agent.client.bus_subscribe(agent.id, "tasks.*").await?; // let messages = agent.client.bus_poll(agent.id).await?; }
Coordinating via Blackboard
#![allow(unused)] fn main() { // Parent writes task specification agent.client.send(Request::BlackboardWrite { agent_id: agent.id, key: format!("task.{}.spec", child_id), value: json!({"query": "renewable energy"}), ttl_secs: Some(300), }).await?; // Child reads it (in child's code): // agent.client.send(Request::BlackboardRead { ... }) // Parent polls for results loop { let response = agent.client.send(Request::BlackboardRead { agent_id: agent.id, key: format!("task.{}.result", child_id), }).await?; if let Response::BlackboardValue { value: Some(result), .. } = response { println!("Child result: {}", result); break; } tokio::time::sleep(std::time::Duration::from_secs(1)).await; } }
Hierarchy Constraints
- A child agent's trust level cannot exceed its parent's trust level
- Escalations from the child route to the parent automatically (no code needed)
- The parent can terminate the child with
Request::TerminateAgent { agent_id: child_id }