Execute a task using a caller-supplied task id. Used by `execute_background` so the synchronously-returned task id matches the one in lifecycle events. When `emit_start` is `false` the caller is responsible for emitting `SubagentStart` themselves (e.g. to avoid a race against a tracker query).
(
&self,
task_id: String,
params: TaskParams,
event_tx: Option<broadcast::Sender<AgentEvent>>,
parent_session_id: Option<&str>,
emit_start: bool,
)
| 282 | /// When `emit_start` is `false` the caller is responsible for emitting |
| 283 | /// `SubagentStart` themselves (e.g. to avoid a race against a tracker query). |
| 284 | pub async fn execute_with_task_id( |
| 285 | &self, |
| 286 | task_id: String, |
| 287 | params: TaskParams, |
| 288 | event_tx: Option<broadcast::Sender<AgentEvent>>, |
| 289 | parent_session_id: Option<&str>, |
| 290 | emit_start: bool, |
| 291 | ) -> Result<TaskResult> { |
| 292 | let session_id = format!("task-run-{}", task_id); |
| 293 | |
| 294 | let agent = self |
| 295 | .registry |
| 296 | .get(¶ms.agent) |
| 297 | .context(format!("Unknown agent type: '{}'", params.agent))?; |
| 298 | |
| 299 | if emit_start { |
| 300 | if let Some(ref tx) = event_tx { |
| 301 | let _ = tx.send(AgentEvent::SubagentStart { |
| 302 | task_id: task_id.clone(), |
| 303 | session_id: session_id.clone(), |
| 304 | parent_session_id: parent_session_id.unwrap_or_default().to_string(), |
| 305 | agent: params.agent.clone(), |
| 306 | description: params.description.clone(), |
| 307 | }); |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | // Build a child ToolExecutor. Task tools are intentionally omitted |
| 312 | // here to prevent unlimited delegation nesting. |
| 313 | let child_executor = if let Some(ref parent_ctx) = self.parent_context { |
| 314 | if let Some(ref services) = parent_ctx.workspace_services { |
| 315 | crate::tools::ToolExecutor::new_with_workspace_services_and_artifact_limits( |
| 316 | self.workspace.clone(), |
| 317 | Arc::clone(services), |
| 318 | crate::tools::ArtifactStoreLimits::default(), |
| 319 | ) |
| 320 | } else { |
| 321 | crate::tools::ToolExecutor::new(self.workspace.clone()) |
| 322 | } |
| 323 | } else { |
| 324 | crate::tools::ToolExecutor::new(self.workspace.clone()) |
| 325 | }; |
| 326 | |
| 327 | // Register MCP tools so child agents can access MCP servers. |
| 328 | if let Some(ref mcp) = self.mcp_manager { |
| 329 | let all_tools = mcp.get_all_tools().await; |
| 330 | let mut by_server: std::collections::HashMap< |
| 331 | String, |
| 332 | Vec<crate::mcp::protocol::McpTool>, |
| 333 | > = std::collections::HashMap::new(); |
| 334 | for (server, tool) in all_tools { |
| 335 | by_server.entry(server).or_default().push(tool); |
| 336 | } |
| 337 | for (server_name, tools) in by_server { |
| 338 | let wrappers = |
| 339 | crate::mcp::tools::create_mcp_tools(&server_name, tools, Arc::clone(mcp)); |
| 340 | for wrapper in wrappers { |
| 341 | child_executor.register_dynamic_tool(wrapper); |
no test coverage detected