Skip to main content
A workflow is the ordered list of steps on your agent. A step is one thing a agent must finish, such as getting the caller’s name. A step only ends when your tool records its answer, so the model can’t skip ahead. A workflow left to right: the call starts in the intake subagent, which runs its patient and visit steps in order. on_exit moves the call to the scheduling subagent, which runs its slot and confirm steps, and then the call ends. Each arrow between steps is your tool calling self.complete(...). After a subagent’s last step, its on_exit moves the call on.

Add Steps

List a subagent’s steps in steps. Each answer is a dataclass, and a tool ends the step with self.complete(...).
Callers often answer ahead. If your tool completes a later step early, the answer is kept and that step isn’t asked.

Steps Without Subagents

If one agent does the whole call, give the agent its steps with workflow=. Its own tools finish them with self.complete(...).
An agent takes workflow= or subagents=, not both. Subagents with no steps don’t need a workflow at all: each transfer_to is a plain agent handoff, and any runtime runs it.

Read Answers

Use the step’s id on self.workflow. For another subagent’s step, add its name. A step with no answer reads as None.

Optional and Conditional Steps

Add optional=True to let the caller decline a step. The model skips it for you. Add a condition to run a step only for some callers:
A field is <step>.<key> from the same subagent, or userdata.<key> from the call’s metadata. You can use eq, ne, in, not_in, or exists, and combine them with all, any, and not.

Retry a Step

Set max_attempts to limit retries. Each {"error": ...} from a subagent’s tool counts as one attempt. At the limit, on_step_failed runs:

Change an Answer

Use go_to_step when the caller changes their mind. Use "<subagent>.<step>" to go back to another subagent’s step.
Only that step is asked again. If the answer changes, the steps in later subagents are done again. If the caller gives the new answer straight away, skip go_to_step: call self.complete(...) with it. The finished step is updated and the call carries on from where it was.

Track Progress

Events tell your code what just happened on the call, so you can log progress or save answers to your own systems. They stay in your agent: the model doesn’t see them, and they aren’t sent to the room. result is the answer as a dict. progress lists that subagent’s steps as done, skipped, and to_do. A skipped step has no event of its own, so look for it in progress. Listen on your agent:
Or use @on_workflow on a subagent. It hears every subagent’s events, so check data["agent"] if you only want its own.

What’s Next

Subagents

Roles, hooks, and moving the call.

Clinic Example

A full call with retries, corrections, and events.