Skip to main content
Conditional execution gates tasks and workflow steps on runtime values using one when syntax that works in both AgentFlow pipelines and Task teams.
Runtime support: Task(when=..., then_task=..., else_task=...) and Task(routing=...) are wired into the markdown workflow engine (WorkflowManager, .praisonai/workflows/*.md). Run them with praisonai workflow run <file>.md or WorkflowManager.execute(...) — the runtime that honours these fields. See Markdown Workflow Branches for a runnable branch example.
The user defines workflows; when expressions gate tasks and AgentFlow steps on runtime variables.
Since PraisonAI PR #4020, when/then_task/else_task routing is wired into PraisonAIAgents. On earlier releases the API existed on Task but the Process orchestrator never consulted it — when-only tasks silently stalled or fell through to unrelated tasks.

Overview

Conditional execution allows you to control workflow branching based on variables, scores, or other runtime values. PraisonAI supports:
  • String expression conditions - Simple {{variable}} syntax for comparisons
  • Dictionary routing - Map decision values to next tasks
  • Callable conditions - Custom Python functions

Quick Start

1

Task or AgentFlow

Condition Syntax

String Expression Conditions

Use {{variable}} placeholders with comparison operators:
String comparisons don’t require quotes: {{status}} == approved works correctly.

Examples

Task Condition Parameters

when Parameter

The when parameter accepts a string expression condition:

then_task and else_task

Route to different tasks based on condition result:

routing Parameter (Advanced)

For LLM-driven decisions, use the routing parameter (formerly condition). Pass a bare dict, or the TaskRoutingConfig dataclass for clarity:
TaskRoutingConfig(...) unpacks onto Task.branch_condition and Task.next_steps — the attributes the executor reads — so Task.condition stays a plain dict/str.

Precedence Ladder

The routing parameter resolves in this order (only the last two forms are supported today):
Precedence: Bool > String > Dict > Config — the markdown engine honours the Dict and Config forms.
The condition parameter still works for backward compatibility, but routing is preferred for clarity.

End-to-End Markdown Example

A branch actually being taken in a markdown workflow:
classify_and_route.md
When step1’s output contains success, execution jumps to handle_success, skipping handle_failure.

should_run Callable

For complex logic, use a callable:
As of PraisonAI PR #4907, should_run is honoured uniformly by both PraisonAIAgents / AgentTeam and the standalone Workflow engine — a falsy return skips the task and records an empty result so downstream tasks can tell a skip from a real empty run. Earlier releases silently ignored should_run under PraisonAIAgents.

AgentFlow Conditions

when() Function

Nested Conditions

Multi-agent Workflows (PraisonAIAgents)

when/then_task/else_task also routes multi-agent workflows built with PraisonAIAgents.

should_run under PraisonAIAgents

A should_run gate composes directly with PraisonAIAgents(...).start() — a falsy return skips the task.
An async def gate is awaited natively on the async path and resolved to completion on the sync path.
How the routing context is built — the when expression is evaluated against the current task (the one that just completed), not the target:
  • The context is result.to_dict() (from json_dict / pydantic) merged with previous_output = result.raw.
  • Access structured fields as {{field_name}} (e.g. {{score}} when the agent returns {"score": 90}).
  • Access raw text as {{previous_output}}.
Priority — when both when and next_tasks are set on the same task, when-routing wins.
Clean termination — if the taken branch resolves to None (e.g. only then_task is set and the condition is false, with no next_tasks fallback), the workflow ends cleanly on that path. It does not pick an unrelated not-started task.

Flow Diagram

How It Works


Best Practices

Keep conditions readable and simple. Complex logic should go in should_run callables.
Specify both branches when you want an explicit fork:
When the LLM needs to make a decision, use routing with task_type="decision":
The router normalises the model’s output with .lower().strip() before the lookup, so any key that carries uppercase letters, surrounding whitespace, or punctuation falls through to the silent exit branch.
Silent-exit pitfall — an unmatched decision and a deliberate exit take the same branch, with no exception and no warning. If your workflow finishes on the first pass when you expected a retry loop, the judge’s verdict probably didn’t match any key in routing/condition. Check the Workflow exit condition met on decision: log line to see the exact normalised key the router tried, then add it (lowercase, whitespace-free) to your routing map. See Task Validation & Feedback for the full deep dive.

Migration Guide

From condition to routing

Adding when to existing Tasks

API Reference

Task Parameters

Task Methods

Markdown Workflow Branches

Route markdown-workflow steps on output

Tasks

Task fields including when / then_task / else_task

AgentFlow

Learn about deterministic pipelines

AgentTeam

Multi-agent task orchestration