A workflow run executes a coordination script that fans work out across helper agents and returns one value. This page is the reference for writing and debugging such scripts: how a run ends, what its result carries, the limits it works within, and the failures it can report. For what a workflow is and how a run starts, see The workflow tool.
A run settles once, with exactly one stop reason:
| Stop reason | What it means |
|---|---|
| completed | The script finished and its return value came back. |
| cancelled | The run was stopped, with a reason where one was given. |
| error | The run failed; the error says how. |
null and the script decides what to do with it. The faults that do end the run are listed below.| Limit | Value | What it bounds |
|---|---|---|
| Agent concurrency | Resolved from the machine's available CPU parallelism | How many agent calls run at the same time |
| Total agent calls | 1,000 per run | How many calls one run may start |
| Items per call | 4,096 | How many items one fan-out call may take |
| Initial synchronous slice | 5,000 ms | The stretch of a script that runs before it first yields |
| Overall deadline | None | A run has no elapsed-time limit |
The caps are cooperative backstops for runaway work, not security quotas.
Each failure below stops the run and is reported in its error.
meta block written inside the script body is refused with a message that points to the request's meta field. The message starts workflow script does not parse and names the problem.Script execution timed out; progress the script already sent is kept.non-finite numbers are not JSON data. The message asks for JSON-serializable objects, arrays and scalars.meta block is checked before the run starts: unknown fields are refused by name (meta. <key> is not a recognized field (name/ description/ whenToUse/ phases)), the name and description must be non-empty, and every phase needs a title. All violations are named at once in one invalid meta message, not just the first.agent() requires a non-empty prompt string), options that are not an object, an option outside the supported set, a schema outside the supported subset, or a provider that cannot start the child (agent() could not start a child). The supported options are label, phase, schema, provider and model; effort, isolation and agentType are deferred and refused as not supported by this engine.child agent run failed. This is different from a child that simply failed, which hands back null as described above.no subagent provider registered for "<provider>"), and a total-agent ceiling must be a positive whole number that does not exceed the engine's ceiling.workflow run cancelled: <reason>. With no reason given, the reason reads workflow cancelled; when the calling step was stopped, parent step aborted; when the run's abort signal fired, workflow signal aborted.A top-level run writes four records into the chat's log as it goes: the run's start, an agent's start and end for each call, and the run's end.
The run's error names the failure: a script that does not parse, a script whose initial synchronous slice timed out, a return value that is not plain JSON, meta that fails validation, a call that could not start or whose result could not come back, a cap reached, or an up-front validation refusal. A stopped or failed run never presents partial output as a successful result.
No. A run has no overall elapsed-time limit: it keeps going until it completes, fails or is stopped. The one timed stretch is the script's initial synchronous slice, bounded at 5,000 ms; work that yields, such as agent calls, is not under that bound.
The run started more agent calls than its total-agent ceiling allows, 1,000 by default. It is a backstop against runaway loops: the run ends, and the message says the limit can be raised if the scale is intentional. A run can come with a lower ceiling of its own, but nothing raises one above the engine's.
A child that failed on its own, including one that missed the structured result you asked for, hands back null; the script decides what to do with it. Only faults around the call itself, a provider that cannot start the child or a child result that cannot come back, end the run.
Values that cannot cross back are refused: non-finite numbers, bigints, functions, symbols, an undefined inside a container, circular references, sparse arrays and objects with exotic prototypes. Return plain objects, arrays and scalars.
The script's initial synchronous slice, the part before it first yields, ran past 5,000 ms; a loop that never yields trips this bound. Progress already sent is kept. Long stretches belong behind awaited work such as agent calls, so the script leaves its opening slice.
They end as cancelled, one ending per started call. A child that only becomes ready after the stop is disposed without making a request, and the run settles only after the script and its children are cleaned up.
No. It settles once, with the first accepted outcome; a stop after that does not rewrite it, and the result never rejects.
Four records: the run's start, each agent's start and end, and the run's end. They are observational: they stay out of the conversation and never reach a model request. An agent's start is recorded before the child's first request, and the run's end only after the result and the cleanup have settled.
The ceilings come from the engine's configuration in the deployment; a run can lower its own total-agent ceiling, but nothing raises a ceiling above the engine's. Concurrency is resolved from the machine's available CPU parallelism by default.