Documentation Index
Fetch the complete documentation index at: https://docs.syllable.ai/llms.txt
Use this file to discover all available pages before exploring further.
Building on input collection, this example chains multiple steps together to create a complete contact form workflow.
Objective
In this example, you’ll learn:
- How to connect multiple steps using the
next field
- How to persist data across steps with the
save action
- The difference between transitional and terminal steps
- How workflow state evolves as steps complete
The Scenario
You want to build a contact form that collects:
- User’s name
- Email address
- Preferred contact time
Each piece of information is collected in a separate step, and the data persists across the entire workflow.
Implementation
Here’s the complete tool definition:
{
"type": "context",
"context": {
"task": {
"type": "steps",
"version": "v1alpha",
"id": "contact-form",
"tool": {
"name": "submit_contact_info",
"description": "Submit contact form information"
},
"steps": [
{
"id": "COLLECT_NAME",
"goal": "Collect the user's name",
"instructions": [
"Ask the user for their name.",
"Once you have their name, call the submit_contact_info tool with the user_name parameter."
],
"inputs": [
{
"name": "user_name",
"type": "string",
"description": "The user's name",
"required": true
}
],
"on": {
"submit": [
{"action": "save"}
]
},
"next": [{"id": "COLLECT_EMAIL"}]
},
{
"id": "COLLECT_EMAIL",
"goal": "Collect the user's email address",
"instructions": [
"Ask the user for their email address.",
"Once you have their email, call the submit_contact_info tool with the user_email parameter."
],
"inputs": [
{
"name": "user_email",
"type": "string",
"description": "The user's email address",
"required": true
}
],
"on": {
"submit": [
{"action": "save"}
]
},
"next": [{"id": "COLLECT_TIME"}]
},
{
"id": "COLLECT_TIME",
"goal": "Collect the user's preferred contact time",
"instructions": [
"Ask the user for their preferred contact time.",
"Once you have their preference, call the submit_contact_info tool with the contact_time parameter."
],
"inputs": [
{
"name": "contact_time",
"type": "string",
"description": "The user's preferred contact time",
"required": true
}
],
"on": {
"submit": [
{"action": "save"}
]
}
}
]
}
},
"tool": {
"type": "function",
"function": {
"name": "contact_form_workflow",
"description": "Multi-step workflow with sequential input collection",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
}
}
Key Concepts
Step Transitions with next
The next field defines which step to go to after successful submission:
"next": [{"id": "COLLECT_EMAIL"}]
Key behaviors:
- Evaluated after validation passes: The workflow only transitions if all required inputs are present
- Evaluated in order: If multiple entries exist, the first matching one wins (more on this in Example 5)
- Terminal if missing: A step without
next ends the workflow
The save Action
By default, inputs are cleared when transitioning to a new step. The save action persists them:
"on": {
"submit": [
{"action": "save"}
]
}
Without parameters: Saves all step inputs to global variables with matching names.
With specific inputs:
{"action": "save", "inputs": ["user_name", "user_email"]}
With a custom name:
{"action": "save", "name": "contact_info.name", "inputs": ["user_name"]}
Transitional vs Terminal Steps
| Step Type | Has next | Behavior |
|---|
| Transitional | Yes | Moves to next step after submission |
| Terminal | No | Completes workflow after submission |
In this example:
COLLECT_NAME → transitional (goes to COLLECT_EMAIL)
COLLECT_EMAIL → transitional (goes to COLLECT_TIME)
COLLECT_TIME → terminal (ends workflow)
As the workflow progresses, the submit tool’s schema changes:
At COLLECT_NAME:
{
"name": "submit_contact_info",
"description": "Collect the user's name",
"parameters": {"properties": {"user_name": {...}}}
}
At COLLECT_EMAIL:
{
"name": "submit_contact_info",
"description": "Collect the user's email address",
"parameters": {"properties": {"user_email": {...}}}
}
The agent always sees the correct schema for the current step.
How It Works
Here’s the conversation flow:
User: "Hello"
[Platform initializes workflow]
→ Current step: COLLECT_NAME
Agent: "Could you please tell me your name?"
User: "My name is Alice"
[Agent calls submit_contact_info(user_name="Alice")]
→ save action: user_name → global variable
→ next: transition to COLLECT_EMAIL
→ inputs cleared for new step
Agent: "Thank you, Alice! Now, could you please provide your email address?"
User: "alice@example.com"
[Agent calls submit_contact_info(user_email="alice@example.com")]
→ save action: user_email → global variable
→ next: transition to COLLECT_TIME
Agent: "Great! What is your preferred contact time?"
User: "morning"
[Agent calls submit_contact_info(contact_time="morning")]
→ save action: contact_time → global variable
→ no next field (terminal)
→ workflow completes
Agent: "Thank you! I have all your information."
State Evolution
After Step 1 (COLLECT_NAME):
{
"current_step_id": "COLLECT_EMAIL",
"completed_steps": ["COLLECT_NAME"],
"workflow_completed": false,
"global_variables": {
"user_name": "Alice"
}
}
After Step 2 (COLLECT_EMAIL):
{
"current_step_id": "COLLECT_TIME",
"completed_steps": ["COLLECT_NAME", "COLLECT_EMAIL"],
"workflow_completed": false,
"global_variables": {
"user_name": "Alice",
"user_email": "alice@example.com"
}
}
After Step 3 (COLLECT_TIME):
{
"current_step_id": "COLLECT_TIME",
"completed_steps": ["COLLECT_NAME", "COLLECT_EMAIL", "COLLECT_TIME"],
"workflow_completed": true,
"global_variables": {
"user_name": "Alice",
"user_email": "alice@example.com",
"contact_time": "morning"
}
}
Try It
To test this workflow in the Syllable Console:
- Create a new tool with the JSON above
- Assign it to an agent
- Start a conversation and say “hello”
- Provide your name when asked
- Provide your email when asked
- Provide your preferred time when asked
- Observe the workflow completing after all three steps
What’s Next
This example creates a functional contact form, but the experience feels robotic—no greeting, no sense of progress. In Example 4: Lifecycle Actions, you’ll learn how to:
- Add welcome messages with
on.enter hooks
- Display progress indicators (“Step 1 of 3”)
- Use the
say action for verbatim text delivery
- Track progress with counters