About model-down benching
When an agent's remote model goes away — a removed endpoint, a decommissioned
model id, a provider returning 404 Not Found — every task routed to that agent
fails the same way. Left unchecked, the scheduler keeps handing that agent work
it cannot do, and each job it joins loses a candidate. In the worst case a job
collapses to a single proposer, or to none.
Benching is how an agent removes itself from scheduling until its model comes back, without any central health-checker having to probe it.
How it works
The agent's own task loop is the health signal. A task that fails with a
model-unavailable error (is_model_down_error — anchored on the HTTP status
phrase and known "model not found" messages, so a bare 404 inside a job id
does not trip it) arms a cooldown deadline. The heartbeat reports model_down
while the deadline is in the future, and the orchestrator's scheduler skips a
model_down agent. When the deadline passes the flag clears automatically, so a
transient outage does not bench the agent forever.
stateDiagram-v2
[*] --> Up
Up --> Down: task fails model-unavailable\n(strike++, bench = base × 2^(strike-1))
Down --> Up: cooldown deadline passes
Up --> Up: task succeeds\n(strikes reset to 0)Why the bench escalates
A fixed cooldown re-admits a permanently-dead model on every cycle: it is benched, the deadline passes, the scheduler assigns it, the task 404s, it is benched again — one failed job per cooldown, forever. In production this showed up as a single agent joining seven jobs and proposing in none.
So the bench duration escalates with consecutive strikes —
escalated_cooldown_ms doubles the base per strike (5 min → 10 → 20 → …) capped
at 30 minutes. A chronically-dead model backs off toward the cap and stops
churning the scheduler; the operator has time to fix or remove it.
The escalation is fail-safe because any successful task resets the strike count to zero. A model that recovers proves it by completing one task, and its next (if any) failure waits only the base cooldown — the escalation never punishes a working model, only a persistently-failing one.
What benching is not
Benching is a scheduling hint, not a verdict. The orchestrator stays
reason-agnostic — it never learns why the agent is down, only that it should
not wait for it. The actual upstream error lives agent-side:
an operator reads it from GET /api/agents/{name}/diagnostics
(see how-to: expose the agent dashboard),
where the recent_errors list carries the real 404 and the rising strike
count shows a model that is not recovering. Fixing or removing a chronically-
dead agent is the operator's call, not the orchestrator's.