(
&self,
spec: AgentStepSpec,
event_tx: Option<broadcast::Sender<AgentEvent>>,
)
| 562 | #[async_trait] |
| 563 | impl AgentExecutor for TaskExecutor { |
| 564 | async fn execute_step( |
| 565 | &self, |
| 566 | spec: AgentStepSpec, |
| 567 | event_tx: Option<broadcast::Sender<AgentEvent>>, |
| 568 | ) -> StepOutcome { |
| 569 | let agent = spec.agent.clone(); |
| 570 | let task_id = spec.task_id.clone(); |
| 571 | let output_schema = spec.output_schema.clone(); |
| 572 | let params = TaskParams { |
| 573 | agent: spec.agent, |
| 574 | description: spec.description, |
| 575 | prompt: spec.prompt, |
| 576 | background: false, |
| 577 | max_steps: spec.max_steps, |
| 578 | }; |
| 579 | let mut outcome: StepOutcome = match self |
| 580 | .execute_with_task_id( |
| 581 | task_id.clone(), |
| 582 | params, |
| 583 | event_tx, |
| 584 | spec.parent_session_id.as_deref(), |
| 585 | true, |
| 586 | ) |
| 587 | .await |
| 588 | { |
| 589 | Ok(result) => result.into(), |
| 590 | Err(e) => return StepOutcome::failed(task_id, agent, format!("Task failed: {e}")), |
| 591 | }; |
| 592 | |
| 593 | // When the step requested structured output, coerce the (succeeded) |
| 594 | // free-text result to the schema. A coercion failure demotes the step |
| 595 | // to unsuccessful so callers never treat unvalidated text as the |
| 596 | // promised object. |
| 597 | if outcome.success { |
| 598 | if let Some(schema) = output_schema { |
| 599 | match self.coerce_to_schema(&outcome.output, schema).await { |
| 600 | Ok(object) => outcome.structured = Some(object), |
| 601 | Err(e) => { |
| 602 | outcome.success = false; |
| 603 | outcome.output = |
| 604 | format!("{}\n\n[structured output failed: {e}]", outcome.output); |
| 605 | } |
| 606 | } |
| 607 | } |
| 608 | } |
| 609 | outcome |
| 610 | } |
| 611 | |
| 612 | fn concurrency_hint(&self) -> usize { |
| 613 | self.max_parallel_tasks |
no test coverage detected