Recurgent uses one runtime path for dynamic calls: tolerant Outcome envelopes.
Every dynamic method call returns Agent::Outcome.
{
status: :ok | :error,
value: Object, # present when status == :ok
error_type: String, # provider | invalid_code | execution | timeout | budget_exceeded
error_message: String, # present when status == :error
retriable: true | false,
tool_role: String,
method_name: String
}- Keep Tool Builder flows alive across Tool failures.
- Make typed failures explicit without collapsing the full solve loop.
- Preserve LLM-native reasoning continuity via one predictable return shape.
- Keep delegation semantics coherent by preferring
delegate(...)inside Tool Builder flows.
- Tool success:
outcome.ok? == trueoutcome.valuecarries domain result.
- Provider returns nil/blank code:
outcome.error? == trueoutcome.error_type == "invalid_code"
- Generated code raises:
outcome.error? == trueoutcome.error_type == "execution"
- Delegation budget exhausted:
outcome.error? == trueoutcome.error_type == "budget_exceeded"- Tool Builder continues synthesis with partial outcomes.