> ## Documentation Index
> Fetch the complete documentation index at: https://docs.julep.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Types of Task Steps

> Learn about different types of task steps and their use

## Overview

In Julep broadly speaking there are two types of steps:

<CardGroup cols={2}>
  <Card title="Control Flow Steps" icon="code-branch" href="#control-flow-steps">
    <p>These steps control the flow of the task. They are used to create conditional logic, loops, and parallel execution.</p>
  </Card>

  <Card title="Key-Value Steps" icon="database" href="#key-value-steps">
    <p>These steps are used to get and set values in the task.</p>
  </Card>

  <Card title="Iteration Steps" icon="arrows-spin" href="#iteration-steps">
    <p>These steps are used to iterate over a collection.</p>
  </Card>

  <Card title="Conditional Steps" icon="code-branch" href="#conditional-steps">
    <p>These steps are used to create conditional logic.</p>
  </Card>

  <Card title="Other Control Flow Steps" icon="code-branch" href="#other-control-flow">
    <p>These steps are used to control the flow of the task.</p>
  </Card>
</CardGroup>

<Note>
  The steps defined out here are in the YAML format. You can learn more about the YAML format [here](https://yaml.org/spec/1.2.2/).
</Note>

## Control Flow Steps

### Prompt Step

Send messages to the AI model:

```yaml YAML theme={"dark"}
# Simple prompt
- prompt: What is your name?

# Multi-message prompt
- prompt:
    - role: system
      content: You are a helpful assistant
    - role: user
      content: "Hello!"

# Prompt with settings
- prompt:
    - role: user
      content: Generate a creative story
  settings:
    model: "claude-3.5-sonnet"
    temperature: 0.8

# Prompt with automatic tool execution
- prompt: What's the weather in San Francisco?
  auto_run_tools: true  # Tools execute automatically if needed

# Prompt with JSON response format
- prompt:
    - role: system
      content: You are a helpful assistant that always responds in JSON format.
    - role: user
      content: List 3 interesting facts about space. Format as JSON with 'facts' array.
  settings:
    model: "gpt-4o-mini"
    temperature: 0.7
    response_format:
      type: json_object

# Prompt with JSON schema for structured output
- prompt:
    - role: system
      content: You are a data extraction specialist.
    - role: user
      content: Extract product information from the description.
  settings:
    response_format:
      type: json_schema
      json_schema:
        name: product_info
        schema:
          type: object
          properties:
            product_name:
              type: string
            features:
              type: array
              items:
                type: string
            price:
              type: number
          required: ["product_name", "features", "price"]
```

<Note>
  When `auto_run_tools` is set to `true` in a prompt step, any tools available to the agent will be automatically executed if the model decides to use them. The results are then fed back to the model to continue processing. This is particularly useful for creating autonomous workflows where the agent can gather information and make decisions without manual intervention.
</Note>

<Note>
  The `response_format` setting allows you to request structured output from the model. There are two main options:

  * `type: json_object` - Ensures the model responds with valid JSON
  * `type: json_schema` - Enforces a specific JSON structure defined by a schema

  When using `response_format`, make sure to instruct the model to produce JSON in your prompt (via system or user message) for best results. Response format support varies by model provider - check the [supported models documentation](/integrations/supported-models) for compatibility.
</Note>

<Info>
  In the prompt step we offer a bunch of Python functions to help you manipulate data. Here is a list of the functions you can use:

  * Standard library modules:
    * `re`: Regular expressions (safe against ReDoS)
    * `json`: JSON encoding/decoding
    * `yaml`: YAML parsing/dumping
    * `string`: String constants and operations
    * `datetime`: Date and time operations
    * `math`: Mathematical functions
    * `statistics`: Statistical operations
    * `base64`: Base64 encoding/decoding
    * `urllib`: URL parsing operations
    * `random`: Random number generation
    * `time`: Time operations

  * Constants:
    * `NEWLINE`: Newline character
    * `true`: Boolean true
    * `false`: Boolean false
    * `null`: None value
</Info>

### Tool Call Step

Execute tools defined in the task:

```yaml YAML theme={"dark"}
# Simple tool call
- tool: web_search
  arguments:
    query: Latest AI news

# Tool call with complex arguments
- tool: process_data
  arguments:
    input_data: $ _.previous_result
    options:
      format: "json"
      validate: true
```

### Evaluate Step

Perform calculations or data manipulation:

```yaml YAML theme={"dark"}
# Simple evaluation
- evaluate:
    count: $ len(_.results)

# Multiple evaluations
- evaluate:
    total: $ sum(_.numbers)
    average: $ _.total / len(_.numbers)
    formatted: $ f'Average: {_.average:.2f}'
```

<Info>
  In the evaluate step we offer a bunch of Python functions to help you manipulate data. Check out the [Python Expressions](/advanced/python-expression#available-functions-and-libraries) for more information.
</Info>

### Wait for Input Step

Pause workflow for user input:

```yaml YAML theme={"dark"}
# Simple input request
- wait_for_input:
    info:
      message: "Please provide your name"

# Input with validation
- wait_for_input:
    info:
      message: "Enter your age"
      validation:
        type: "number"
        minimum: 0
        maximum: 150
```

### Subworkflow Step

Executing a subworkflow from a main workflow:

```yaml YAML [expandable] theme={"dark"}
# Subworkflow
subworkflow:
- evaluate:
    main_workflow_input: $ _.content # you can use steps[0].input.content to access the input of the subworkflow
- return:
    result: "This is the subworkflow"

# Main workflow
main:
# Step 0: Evaluate step
- evaluate:
    result: "This is the main workflow"

# Step 1: Call the subworkflow
- workflow: subworkflow # name of the subworkflow
  arguments: # input to the subworkflow
    content: $ _.result # you can use steps[0].output.result to access the result of the previous step

# Step 2: Evaluate step
- evaluate:
    subworkflow_result: $ steps[1].output.result # this will be the result of the subworkflow
```

<Note>
  * The `arguments` passed from the main workflow to the subworkflow are available in the `steps[0].input` of the subworkflow.
  * The `result` of the subworkflow is available in the `steps[1].output.result` of the main workflow.
  * The `Input/Output Data References` between steps is exclusive to the workflow they are defined in.
    A workflow cannot reference the `input` or `output` of another workflow between the steps. To learn more about `Input/Output Data References` [click here](/advanced/new-syntax#1-input-output-data-references).
</Note>

<Info>
  Self recursion is allowed in a subworkflow but not in a main workflow.
</Info>

## Key-Value Steps

### Get Step

Retrieve values from storage:

```yaml YAML theme={"dark"}
# Get a single value
- get: user_preference

# Get multiple values
- get:
    - preference1
    - preference2
```

### Set Step

Store values for later use:

```yaml YAML theme={"dark"}
# Set a single value
- set:
    user_name: John

# Set multiple values
- set:
    count: $ len(_.results)
    has_data: $ _.count > 0
```

Values stored using the set step are added to the workflow's global `state` object, which can be accessed anywhere in the workflow using `state.variable_name`. For example:

```yaml YAML theme={"dark"}
# Access previously set values
- evaluate:
    greeting: $ f"Hello, {state.user_name}!"
    data_status: $ f"Has data: {state.has_data}, Count: {state.count}"
```

<Note>
  Each subworkflow has its own isolated `state` object. Values set in one subworkflow are not accessible from other subworkflows or the parent workflow.
</Note>

### Label Step

Label a step to make it easier to identify and access those values later in any step:

```yaml YAML theme={"dark"}
# Step 0: Set a single value
- set:
    user_name: John
  label: get_user_name

# Step 1: Set multiple values
- set:
    count: $ len(_.results)
    has_data: $ _.count > 0
  label: get_count_and_has_data
```

In any steps following the label step, you can access the values set in the label step using the `$ steps['label_name'].input.attribute_name` or `$ steps['label_name'].output.attribute_name` syntax. For example:

```yaml YAML theme={"dark"}
- evaluate:
    user_name: $ steps['get_user_name'].output.user_name
- evaluate:
    count: $ steps['get_count_and_has_data'].output.count
    has_data: $ steps['get_count_and_has_data'].output.has_data
```

## Iteration Steps

### Foreach Step

Iterate over a collection:

```yaml YAML theme={"dark"}
# Simple foreach
- foreach:
    in: $ _.items
    do:
      log: $ f'Processing {_}'

# Foreach with complex processing
- foreach:
    in: $ _.documents
    do:
      tool: analyze
      arguments:
        text: $ _.content
      evaluate:
        results: $ _ + [_.analysis]
```

### Map-Reduce Step

Process collections in parallel:

```yaml YAML theme={"dark"}
# Simple map-reduce
- over: $ _.urls
  map:
    tool: fetch_content
    arguments:
      url: $ _
  reduce: $ results + [_]

# Map-reduce with parallelism
- over: $ _.queries
  map:
    tool: web_search
    arguments:
      query: $ _
  parallelism: 5 # Number of parallel steps to execute
```

<Note>
  * By default the `parallelism` if not mentioned is 100. If mentioned, it is the maximum number of steps that can run in parallel concurrently.
  * When using `over` step, the `map` step is executed for each value in the collection.
  * The `reduce` step is executed after the `map` step.
</Note>

## Conditional Steps

### If-Else Step

Conditional execution:

```yaml YAML [expandable] theme={"dark"}
# Simple if
- if: $ _.count > 0
  then:
    log: Found results

# If-else
- if: $ _.score > 0.8
  then:
    log: High score
  else:
    log: Low score

# If-else with multiple conditions
- if: $ 1 > 0
  then:
    if: $ 2 > 1
    then:
      evaluate:
        x: y
  else:
    evaluate:
      x: z
```

### Switch Step

Multiple condition handling:

```yaml YAML theme={"dark"}
# Switch statement
- switch:
    - case: $ _.category == "A"
      then:
        - log: Category A
    - case: $ _.category == "B"
      then:
        - log: Category B
    - case: $ _  # Default case
      then:
        - log: Unknown category
```

## Other Control Flow

### Sleep Step

Pause execution:

```yaml YAML theme={"dark"}
# Sleep for duration
- sleep:
    seconds: 30

# Sleep with different units
- sleep:
    minutes: 5
    # hours: 1
    # days: 1
```

### Return Step

Return values from workflow:

```yaml YAML theme={"dark"}
# Simple return
- return: $ _.result

# Structured return
- return:
    data: $ _.processed_data
    metadata:
      count: $ _.count
      timestamp: $ datetime.now().isoformat()
```

### Log Step

Log messages or specific values:

```yaml YAML theme={"dark"}
- log: $ f'Processing completed for item {item_id}'
```

### Error Step

Handle errors by specifying an error message:

```yaml YAML theme={"dark"}
- error: Invalid input provided
```

## Example: Complex Workflow

Here's an example combining various step types:

```yaml YAML [expandable] theme={"dark"}
# yaml-language-server: $schema=https://raw.githubusercontent.com/julep-ai/julep/refs/heads/dev/src/schemas/create_task_request.json
name: Multi-Step Task Demonstration
description: A demonstration of multi-step task processing with research and summarization capabilities.

################################################################################
############################# INPUT SCHEMA #####################################
################################################################################
input_schema:
  type: object
  properties:
    topic:
      type: string
      description: The topic to research and summarize.

################################################################################
############################# TOOLS ############################################
################################################################################

# Describing the tools that will be used in the workflow
tools:
- name: web_search
  type: integration
  integration:
    provider: brave
    setup:
      brave_api_key: "YOUR_BRAVE_API_KEY"

################################################################################
############################# MAIN WORKFLOW ####################################
################################################################################
main:
# Step 0: Generate initial research questions
- prompt:
  - role: system
    content: >-
      $ f'''
      You are a research assistant. Your task is to formulate three specific research questions about the given topic: {steps[0].input.topic}'''
  unwrap: true

# Step 1: Web search for each question
- foreach:
    in: $ _.split('\\n')
    do:
      tool: web_search
      arguments:
        query: $ _

# Step 2: Extract relevant information
- evaluate:
    relevant_info: $ [output for output in _]

# Step 3: Process and summarize information
- if: $ len(_.relevant_info) >= 3
  then:
      prompt:
      - role: system
        content: >-
          $ f'''
          Summarize the following information about {steps[0].input.topic}:
          {_.relevant_info}'''
      unwrap: true
  else:
      prompt:
      - role: system
        content: >-
          $ f'''
          Not enough information gathered. Please provide a brief overview of {steps[0].input.topic} based on your knowledge.'''
      unwrap: true

# Step 4: Record the summary
- log: >-
    $ f'''
    Summary for {steps[0].input.topic}: {_}'''

# Step 5: Prepare final output
- return: 
    summary: $ _
    topic: $ steps[0].input.topic
```

## Best Practices

<CardGroup cols={3}>
  <Card title="Step Organization" icon="folder-tree">
    <ul>
      <li>Group related steps logically</li>
      <li>Use comments to explain complex steps</li>
      <li>Keep step chains focused and manageable</li>
    </ul>
  </Card>

  <Card title="Error Handling" icon="shield-exclamation">
    <ul>
      <li>Use if-else for error conditions</li>
      <li>Provide fallback options</li>
      <li>Log important state changes</li>
    </ul>
  </Card>

  <Card title="Performance" icon="gauge-high">
    <ul>
      <li>Use parallel execution when possible</li>
      <li>Optimize data passing between steps</li>
      <li>Cache frequently used values</li>
    </ul>
  </Card>
</CardGroup>

## Support

If you need help with further questions in Julep:

* Join our [Discord community](https://discord.com/invite/JTSBGRZrzj)
* Check the [GitHub repository](https://github.com/julep-ai/julep)
* Contact support at [hey@julep.ai](mailto:hey@julep.ai)
