Skip to navigation
Plugin Building MasterclassEnd-to-End Course

Compose the Workflow

Separate deterministic backend orchestration from user-facing conversation and expose one useful result.

View as Markdown

Composition is where modular assets become one capability. Use two orchestration layers for different jobs:

  • A compound action coordinates uninterrupted backend execution.
  • A conversation process coordinates interaction with a user.

The Golden Rule

Never place consecutive action activities in a conversation process without collecting a new required slot between them.

If no new required user input is needed, keep the backend sequence in one compound action. An Activity Confirmation Policy can protect that compound-action activity, but confirmation by itself does not justify exposing each backend step. Every action activity exposed in a conversation process can add output to the reasoning engine’s context; a compound action keeps its internal outputs behind one boundary and returns one shaped result.

Context window contents
Instructions
User query
API response 1
~800 tokens
API response 2
~1,200 tokens
API response 3
~600 tokens
API response 4
~900 tokens
Attention per block
↑ attention dead zone ↑
Each response stays in the window permanently. As more accumulate, earlier outputs slide into the dead zone — present but ignored.
Step 0 of 6

Build the Compound Action

A compound action behaves like a typed backend function:

input arguments
↓
ordered steps and control flow
↓
named internal outputs
↓
return.output_mapper

Define Input Arguments

Declare only the values the workflow needs:

feature_request_id:
type: string
new_status:
type: string

The caller maps values into these inputs. Inside the compound action, reference them as data.feature_request_id and data.new_status.

Add Focused Steps

Use supported action blocks and control flow to:

  • Look up the current record.
  • Validate a deterministic precondition.
  • Execute the write.
  • Handle provider errors.
  • Retrieve the final state.
  • Notify a user when the ambient workflow requires a conversational handoff.

Give every useful internal result a descriptive output key.

Return One Public Result

Use return.output_mapper to cross the boundary:

- return:
output_mapper:
feature_request:
id: data.updated_feature_request.id
name: data.updated_feature_request.name
status: data.updated_feature_request.currentStatus

Do not return lookup payloads, raw headers, debug data, or redundant intermediate responses unless the caller needs them.

System Triggers Do Not Supply User Context

A compound action invoked by a webhook or schedule has mapped trigger inputs and earlier step outputs, but no automatic meta_info.user. A conversational caller can provide user context.

Build the Conversation Process

A conversation process contains:

ComponentResponsibility
SlotsCollect or infer typed user inputs
Policies and control flowDecide what must happen before the next activity
Action activitiesInvoke HTTP, script, built-in, LLM, or compound actions available in the editor
Content activitiesDisplay explicit text, knowledge articles, or forms
Data BankStore collected slots and completed activity outputs

Use Action Activities for Operations

An action activity supplies:

  • Input Mapping: parent data → typed action arguments.
  • Output Mapping: action response → exposed process output.
  • Confirmation or execution behavior supported by the activity.

For a compound action:

feature_request_id: data.selected_feature_request.id
new_status: data.target_status.value

Then expose only the compound return:

updated_request:
id: response.feature_request.id
name: response.feature_request.name
status: response.feature_request.status
display_instructions_for_model: >-
Confirm the request name and its new status.

Use Content Activities Deliberately

Use a Content Activity when you must display something explicitly inside the flow:

  • Instructions the user must read before continuing.
  • A knowledge article.
  • A form.
  • An intermediate result that must appear before the next step.

Do not add a final Content Activity merely to restate an action output that the reasoning engine can already present. A form is a special case: it must end its branch.

Add Another Conversational Step Only When Needed

Add another action activity only after the assistant collects a new required slot. If the flow needs confirmation, branching, or explicit display but no new required input between backend calls, keep those calls in one compound action and configure the policy or content around that compound-action boundary.

Understand Synchronous and Asynchronous Work

A compound-action activity configured to wait for completion makes its returned output available to later steps.

A compound-action activity configured as fire-and-forget starts backend work without making its output available downstream. Use it only when the conversation does not need the result.

Shape the Model Boundary

The reasoning engine can present a clean result well when keys carry meaning:

{
"updated_feature_request": {
"name": "Bulk edit requests",
"status": "Planned"
}
}

Avoid sending several implementation-shaped objects:

{
"get_response": {},
"patch_response": {},
"verify_response": {}
}

Use display_instructions_for_model for presentation preferences. Use mappings and deterministic checks for business correctness.

Build Along: Compose the PurpleSuite Workflow

Create a compound action named Update PurpleSuite feature request workflow with this public contract:

PurpleSuite end-to-end call trace

Follow one live feature request through the same three API calls and Agent Studio contracts in every chapter.

Shared connector
https://marketplace.moveworks.com
Every API action
Connector adds Bearer PAT. Action adds X-Instance-ID.
Keep the write and verification behind one boundary
After confirmation, the compound action runs PATCH and GET without another conversational turn.
Map typed inputsMappingConversation activity input mapper
feature_request_id: data.selected_feature_request.id
new_status: data.target_status.value
Receives
selected_feature_request and target_status slots
Returns
feature_request_id and new_status arguments
How it fits
The mapper is the plug between conversation data and reusable backend work. The compound action does not need to know how the values were collected.
Successful run: actual API call ledger
1GET/api/purple-suite/community/feature_requestsDynamic resolver retrieves live candidates
2PATCH/api/purple-suite/community/feature_requests/{id}Compound action updates the selected record
3GET/api/purple-suite/community/feature_requests/{id}Compound action verifies the stored result
Use a record returned by your own PurpleSuite instance. Save its original status before the write and restore it after mutation testing when appropriate.
feature_request_id:
type: string
new_status:
type: string

Inside the compound action:

  1. Call Update PurpleSuite feature request, which runs PATCH /api/purple-suite/community/feature_requests/{id}.
  2. Call Get PurpleSuite feature request, which runs GET /api/purple-suite/community/feature_requests/{id} for the same ID.
  3. Handle provider errors without exposing credentials or raw headers.
  4. Return one feature_request object containing id, name, and status.

Then create a conversation process that:

  1. Collects selected_feature_request.
  2. Collects target_status.
  3. Applies confirmation to the compound-action activity.
  4. Maps both slot values into the compound action.
  5. Exposes the shaped return for the assistant to present.

Your checkpoint is one conversational action boundary. The PATCH and verification operations remain inside the compound action.

The list GET is not part of this compound action. It already ran in the dynamic resolver before confirmation. A successful conversational run therefore produces the call order shown in the trace: list GET, update PATCH, then verification GET.

Composition Decision Table

RequirementPut it in
User must provide a valueSlot in conversation process
User chooses from live API recordsDynamic resolver
User must confirm a writeActivity Confirmation Policy (confirmation_policy)
Several API calls run without interactionCompound action
Loop, parallel branch, or error handlingCompound action
Explicit knowledge article or formContent Activity
Final structured backend resultCompound return.output_mapper
Result exposed to conversationAction Activity Output Mapping

Deep Dives

Next, publish and trigger the plugin.