Workflow Agent Node β Per-Output Retry Configuration#
Overview#
Workflow Agent Nodes (agent_v2) support per-output retry configuration: after the Agent backend returns a result, each declared output is individually type-checked, and any failures can trigger a full node re-run before the configured failure strategy fires. The maximum retry count per output is 10.
This is distinct from model-level rate-limit retries or workflow-level concurrency controls β it operates at the post-execution output-validation layer.
Configuration Model#
Each declared output (DeclaredOutputConfig) carries a failure_strategy containing a DeclaredOutputRetryConfig:
| Field | Type | Default | Constraint |
|---|---|---|---|
enabled | bool | false | β |
max_retries | int | 0 | ge=0, le=10 |
retry_interval_ms | int | 0 | ge=0, le=60_000 |
The le=10 upper bound is enforced by Pydantic at schema load time .
Each output also has an on_failure terminal strategy β applied after all retries are exhausted β with three options defined by OutputErrorStrategy:
STOPβ fail the nodeDEFAULT_VALUEβ substitute a pre-configured default valueFAIL_BRANCHβ route through the node's fail branch outbound edge
OutputFailureOrchestrator#
OutputFailureOrchestrator is the stateless decision engine in api/core/workflow/nodes/agent_v2/output_failure_orchestrator.py. Its single decide() method receives:
failures: a list ofFailedOutputobjects (each wrapping the declared config, failure kind, and reason)current_attempt: zero-indexed attempt number owned by the caller
It returns an OutputFailureOutcome with one of four decisions:
| Decision | Meaning |
|---|---|
RETRY | Re-invoke the entire Agent backend node |
USE_DEFAULT | Replace failed outputs with declared default_value |
FAIL_NODE | Mark node as failed, halt downstream |
TAKE_FAIL_BRANCH | Route through fail branch outbound edge |
Retry budget logic: The effective budget is the maximum max_retries across all currently-failed outputs . If current_attempt < retry_budget, the orchestrator returns RETRY and increments next_attempt. This means retry continues until every failed output's budget is spent .
Multi-output precedence: When multiple outputs fail with different terminal strategies, the highest-precedence strategy wins: FAIL_BRANCH > STOP > DEFAULT_VALUE .
Retry Loop in the Node Runner#
The caller β agent_node._run β owns the attempt counter and the retry loop:
- Run the Agent backend (attempt 0).
- Call
PerOutputTypeChecker.check()on all declared outputs. - Convert
TYPE_CHECK_FAILEDresults toFailedOutputobjects and callorchestrator.decide(). - On
RETRY: updateattempt = outcome.next_attempt, issue a new backend run with a distinct idempotency key, and repeat from step 2. - On
USE_DEFAULT,FAIL_NODE, orTAKE_FAIL_BRANCH: apply terminal handling and exit.
Node inputs are captured only on the first attempt (attempt == 0) so retries don't pollute the inputs payload .
Failure Kinds#
OutputFailureKind has two values:
TYPE_CHECKβ produced byPerOutputTypeChecker: missing required outputs, type mismatches, invalid file referencesOUTPUT_CHECKβ reserved for model-based file content checks (DeclaredOutputCheckConfig), enabled only forFILE-type outputs
Currently, the retry path is triggered by TYPE_CHECK failures. OUTPUT_CHECK infrastructure exists in the config model but is handled by a separate FileOutputCheckExecutor path.
Key Source Files#
| File | Purpose |
|---|---|
api/models/agent_config_entities.py | DeclaredOutputRetryConfig, DeclaredOutputFailureStrategy, OutputErrorStrategy, DeclaredOutputConfig |
api/core/workflow/nodes/agent_v2/output_failure_orchestrator.py | OutputFailureOrchestrator, OutputFailureDecision, retry_idempotency_key |
api/core/workflow/nodes/agent_v2/output_type_checker.py | PerOutputTypeChecker β produces FailedOutput inputs for the orchestrator |
api/core/workflow/nodes/agent_v2/agent_node.py | Retry loop owner; calls orchestrator and manages attempt counter |