New in version 0.11

This example demonstrates how to use termination conditions with the run_until parameter to control the execution of a ControlFlow workflow. We’ll create a simple research workflow that stops under various conditions, showcasing the flexibility of this feature. In this case, we’ll allow research to continue until either two topics are researched or 15 LLM calls are made.

Code

import controlflow as cf
from controlflow.orchestration.conditions import AnyComplete, MaxLLMCalls
from pydantic import BaseModel


class ResearchPoint(BaseModel):
    topic: str
    key_findings: list[str]


@cf.flow
def research_workflow(topics: list[str]):
    if len(topics) < 2:
        raise ValueError("At least two topics are required")

    research_tasks = [
        cf.Task(f"Research {topic}", result_type=ResearchPoint)
        for topic in topics
    ]
    
    # Run tasks with termination conditions
    results = cf.run_tasks(
        research_tasks,
        instructions="Research only one topic at a time.",
        run_until=(
            AnyComplete(min_complete=2)  # stop after two tasks (if there are more than two topics)
            | MaxLLMCalls(15)  # or stop after 15 LLM calls, whichever comes first
        )
    )
    
    completed_research = [r for r in results if isinstance(r, ResearchPoint)]
    return completed_research

Key Concepts

  1. Custom Termination Conditions: We use a combination of AnyComplete and MaxLLMCalls conditions to control when the workflow should stop.

  2. Flexible Workflow Control: By using termination conditions with the run_until parameter, we can create more dynamic workflows that adapt to different scenarios. In this case, we’re balancing between getting enough research done and limiting resource usage.

  3. Partial Results: The workflow can end before all tasks are complete, so we handle partial results by filtering for completed ResearchPoint objects.

  4. Combining Conditions: We use the | operator to combine multiple termination conditions. ControlFlow also supports & for more complex logic.

This example demonstrates how termination conditions provide fine-grained control over workflow execution, allowing you to balance between task completion and resource usage. This can be particularly useful for managing costs, handling time-sensitive operations, or creating more responsive AI workflows.