For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Logo
DeveloperAcademyCommunityStatus
ReferenceGuides
ReferenceGuides
  • Agent Studio
    • Overview
    • Quickstart Guides
    • Core Concepts
    • Conversation Process
    • Actions
      • LLM Actions
      • Built-in Actions
      • HTTP Actions
      • Script Actions
      • Compound Actions
        • Action
        • Switch
        • For Loop
        • Parallel
        • Return
        • Try Catch and Raise Error
        • Notify
        • Input Arguments
        • Progress Updates
        • Compound Action Patterns
        • Compound Action Data Bank
        • Compound Action Examples
        • Troubleshooting Compound Actions
    • Connectors
    • System Triggers
    • Agent Architect
    • Cookbooks
    • Development and Testing
    • AI Agent Marketplace
    • Developer Tools
  • Agentic AI
    • LLM Fundamentals
    • The Agentic Reasoning Engine
    • Memory Constructs
    • Conversational Context
    • Guardrails
    • Grounding and Hallucinations
    • Continuous Learning
    • LLMs & SLMs
    • Steerability Tools
    • Multilingual Support
  • Core Platform
    • User Identity
    • Moveworks Agent (On-Prem)
    • Approvals Engine
    • Entity Catalog
    • Moveworks Data Objects
    • Security Information and Event Management (SIEM) Logs Overview
DeveloperAcademyCommunityStatus
On this page
  • Performing Actions in Batch
  • List of users
  • Usage Compound Action
  • Deduplicating a List
  • Deduplicating a list of scalars
  • Input
  • Usage in Compound Action
  • Result
  • Deduplicating a list of objects
  • Usage in Compound Action
  • Sort Alphabetically
  • Input Arguments
  • Compound Action
  • Result
  • Sort Timestamps
  • Sorting a list of timestamps
  • input
  • Compound Action
  • Result
  • Sorting a list of objects by timestamp
  • Input
  • Compound Action
  • Result
  • Pagination with For Loops
  • Setup
  • Compound Action
  • How It Works
  • Extracting All Results
  • Real-World Example: Polling an API Until Success
  • Easiest way to multiline string usage in YAML
  • Compound Action
Agent StudioActionsCompound Actions

Compound Action Patterns

||View as Markdown|
Was this page helpful?
Edit this page
Previous

Compound Action Data Bank

Next
Built with

This document’s purpose is to accelerate your development process by providing a collection of reusable patterns for common tasks.

Instead of showcasing entire** end-to-end** use cases, this guide focuses on individual, common “steps” you’ll encounter while building. For each pattern, we recommend the most efficient method, whether it’s an LLM action, a Moveworks Data Mapper expression, a DSL query, or a Python Script.

Let’s dive into the patterns.

Performing Actions in Batch

Problem: You want to perform a series of actions repetitively for a list elements. For example, sending a notification to a group of users.

List of users

1{
2 "data": {
3 "email_list": [
4 "jane.doe@example.com",
5 "john_smith88@gmail.com",
6 "alice.w@yahoo.com",
7 "support@mybusiness.net",
8 "data-report-user@company.org",
9 "tester_01@outlook.com"
10 ]
11 }
12}

Usage Compound Action

1steps:
2 - action:
3 action_name: mw.batch_get_users_by_email
4 output_key: list_of_users
5 input_args:
6 user_emails: data.email_list
7 - for:
8 output_key: list_of_notifications
9 each: record
10 in: data.list_of_users.user_records
11 index: idx
12 steps:
13 - notify:
14 output_key: notification_output
15 recipient_id: record.lookup_id
16 message:
17 RENDER():
18 args:
19 user_name: record.user.full_name
20 template: Hi {{user_name}}, you have not submitted your project update this week. Please do before the end of the day!
21 - action:
22 action_name: do_some_action_for_user
23 output_key: action_result
24 input_args:
25 user: record.user
26...

Deduplicating a List

Problem: You have a list that contains duplicate values, and you need a list with only unique elements.

Deduplicating a list of scalars

Input

1{
2 "data": {
3 "duplicated_fruit_list": ["apple", "banana", "cherry", "apple", "banana", "date"]
4 }
5}
1seen = set()
2unique = []
3for x in elements:
4 if x in seen:
5 continue
6 seen.add(x)
7 unique.append(x)
8return unique

Usage in Compound Action

1steps:
2 - action:
3 action_name: deduplicate_list
4 output_key: deduplicate_list_result
5 input_args:
6 elements: data.duplicated_fruit_list
7 - return:
8 output_mapper:
9 unique_list: data.deduplicate_list_result

Result

1{
2 "unique_list": ["apple", "banana", "cherry", "date"]
3}

Deduplicating a list of objects

In this case we will deduplicating a list of objects that have the same email key

1seen = set()
2out = []
3for obj in elements:
4 if not isinstance(obj, dict) or key_field not in obj:
5 continue
6 k = obj[key_field]
7 if k in seen:
8 continue
9 seen.add(k)
10 out.append(obj)
11return out

Usage in Compound Action

1steps:
2 - action:
3 action_name: deduplicate_object_list
4 output_key: deduplicate_list_result
5 input_args:
6 elements: data.input_list
7 key_field: '''email'''
8 - return:
9 output_mapper:
10 unique_list: data.deduplicate_list_result

Sort Alphabetically

Problem: You need to provide a list of elements sorted alphabetically

Input Arguments

1{
2 "data":{
3 "fruits": ["red", "green", "blue", "yellow", "purple"]
4 }
5}

Compound Action

1steps:
2 - action:
3 action_name: enter_fruits_into_system
4 output_key: fruits_result
5 input_args:
6 sorted_fruits:
7 SORT():
8 items: data.fruits
9 key: item

Result

1{
2 "sorted_fruits": [
3 "blue",
4 "green",
5 "purple",
6 "red",
7 "yellow"
8 ]
9}

Sort Timestamps

Problem: You want to sort a list of based on the timestamp

Sorting a list of timestamps

input

1{
2 "data": {
3 "ts": [
4 "Monday, Sep 22, 2025 at 8:15 AM MDT",
5 "Saturday, Sep 20, 2025 at 10:30 AM MDT",
6 "Friday, Sep 19, 2025 at 5:07 PM MDT",
7 "Friday, Sep 19, 2025 at 9:00 PM MDT"
8 ]
9 }
10}

Compound Action

1steps:
2 - action:
3 action_name: enter_timestamps
4 output_key: timestamps_result
5 input_args:
6 sorted_timestamps:
7 SORT():
8 items: data.ts
9 key: item.$PARSE_TIME()

Result

1{
2 "sorted_timestamps": [
3 "Friday, Sep 19, 2025 at 5:07 PM MDT",
4 "Friday, Sep 19, 2025 at 9:00 PM MDT",
5 "Saturday, Sep 20, 2025 at 10:30 AM MDT",
6 "Monday, Sep 22, 2025 at 8:15 AM MDT"
7 ]
8}

Sorting a list of objects by timestamp

Input

1{
2 "data": {
3 "finances": [
4 {
5 "id": "txn_k5p1",
6 "ts": "2025-09-20T10:30:00-06:00",
7 "amount": 2500.0
8 },
9 {
10 "id": "txn_z7h3",
11 "ts": "2025-09-22T08:15:00-06:00",
12 "amount": -29.99
13 },
14 {
15 "id": "txn_8x4f",
16 "ts": "2025-09-19T17:14:04-06:00",
17 "amount": -8.5
18 },
19 {
20 "id": "txn_a2d9",
21 "ts": "2025-09-19T21:00:00-06:00",
22 "amount": 150.75
23 }
24 ]
25 }
26}

Compound Action

1steps:
2 - action:
3 action_name: enter_finances
4 output_key: finances_result
5 input_args:
6 sorted_financials:
7 SORT():
8 items: data.finances
9 key: item.ts.$PARSE_TIME()

Result

1{
2 "sorted_financials": [
3 {
4 "amount": -8.5,
5 "id": "txn_8x4f",
6 "ts": "2025-09-19T17:14:04-06:00"
7 },
8 {
9 "amount": 150.75,
10 "id": "txn_a2d9",
11 "ts": "2025-09-19T21:00:00-06:00"
12 },
13 {
14 "amount": 2500,
15 "id": "txn_k5p1",
16 "ts": "2025-09-20T10:30:00-06:00"
17 },
18 {
19 "amount": -29.99,
20 "id": "txn_z7h3",
21 "ts": "2025-09-22T08:15:00-06:00"
22 }
23 ]
24}

Pagination with For Loops

Problem: You need to paginate through an API that returns results page-by-page using a pagination token (e.g., nextPageToken), but compound actions don’t support while loops.

Solution: Use a for loop with a fixed range (0 to MAX_PAGES), and on each iteration:

  1. Read the pagination token from the previous iteration’s output using index - 1
  2. Use a condition to skip iterations once there are no more pages
  3. Pass the token (or nil for the first page) into the HTTP action

Do not use parallel expressions with this pattern. Because each iteration reads from the previous iteration’s output in the data tree, the loop must execute sequentially.

Why not a while loop? Open-ended while loops are not supported in compound actions for safety reasons — a misconfigured loop could run indefinitely. The for-loop-with-condition pattern gives you the same pagination behavior with a guaranteed upper bound on iterations.

Setup

First, create a helper action (e.g., a Script Action) that generates a range list for the for loop to iterate over:

1# Action: generate_page_range
2# Input: max_pages (int)
3# Output: list of integers [0, 1, 2, ..., max_pages - 1]
4return list(range(max_pages))

Compound Action

1steps:
2 # Step 1: Generate a range to iterate over (e.g., max 10 pages)
3 - action:
4 action_name: generate_page_range
5 output_key: page_range
6 input_args:
7 max_pages: 10
8
9 # Step 2: Paginate through the API
10 - for:
11 each: page
12 index: page_index
13 in: data.page_range
14 output_key: paginated_results
15 steps:
16 - action:
17 action_name: fetch_items_page
18 output_key: fetch_result
19 condition: page_index == 0 OR data.paginated_results[page_index - 1].fetch_result.nextPageToken != nil
20 input_args:
21 page_size: 100
22 pagination_token: IF (page_index == 0) THEN nil ELSE data.paginated_results[page_index - 1].fetch_result.nextPageToken

How It Works

Iterationpage_indexpagination_tokencondition
First0nil (first page, no token needed)true (always runs)
Subsequent1, 2, ...Read from data.paginated_results[page_index - 1].fetch_result.nextPageTokenOnly runs if previous iteration returned a nextPageToken
After last pageNN/Afalse — skips execution since no nextPageToken was returned

Extracting All Results

After the loop completes, you can use a Script Action to flatten all pages into a single list:

1# Action: flatten_paginated_results
2# Input: paginated_results (list of dicts from the for loop)
3all_items = []
4for page in paginated_results:
5 result = page.get("fetch_result")
6 if result and result.get("items"):
7 all_items.extend(result["items"])
8return all_items

Real-World Example: Polling an API Until Success

This same pattern works for polling use cases (e.g., waiting for an Okta push verification):

1steps:
2 - action:
3 action_name: generate_page_range
4 output_key: poll_range
5 input_args:
6 max_pages: 12
7
8 - action:
9 action_name: send_okta_push_verification
10 output_key: push_result
11 input_args:
12 user_id: data.user_id
13
14 - for:
15 each: attempt
16 index: attempt_index
17 in: data.poll_range
18 output_key: poll_results
19 steps:
20 - action:
21 action_name: check_okta_push_status
22 output_key: status_check
23 condition: >
24 attempt_index == 0
25 OR data.poll_results[attempt_index - 1].status_check.factorResult == 'WAITING'
26 input_args:
27 poll_url: data.push_result.poll_url
28 - delay:
29 seconds: 5
30 condition: >
31 data.poll_results[attempt_index].status_check.factorResult == 'WAITING'

Easiest way to multiline string usage in YAML

Problem: You want to a multiline string’s structure to be maintained

Solution: Use Render() and the | character with your template value indented

Compound Action

1result:
2 display_instruction_for_model:
3 RENDER():
4 template: |
5 Each row = one unique order line item in a customer’s purchase.
6 Uniqueness: LINE_ITEM_ID is the primary key (unique per row).
7 Aggregation grain:
8 - Line item–level -> count rows / COUNT(DISTINCT LINE_ITEM_ID)
9 - Order-level -> COUNT(DISTINCT ORDER_ID)
10 - Customer-level -> COUNT(DISTINCT CUSTOMER_ID)
11 - Product-level -> COUNT(DISTINCT PRODUCT_ID)
12 Rule: Always aggregate at the appropriate grain to ensure metrics align correctly with the business question.