Expand description
The unattended loop: take the next task, run the graph, record what happened, take the next one.
This is what turns magi from a command a human types into something an
agent can hand work to. crate::queue is the mailbox; this module is the
thing that empties it. Nothing here decides how a task is implemented —
that is crate::graph — it only decides which task runs next, and what a
finished run means for the task that produced it.
§One run at a time, on purpose
There is no --jobs flag and there will not be one. A single run is
already internally parallel: candidates implement concurrently and judges
rank concurrently, so the machine is not idle while one task is in flight.
The real constraint is not CPU but the agent CLIs’ quota, and two graphs at
once doubles the burn rate on exactly the resource whose exhaustion produces
RunStatus::Stalled. Serialising the loop is what keeps a full backlog
from converting the whole day’s quota into a pile of untrustworthy verdicts.
§A crash is legible
The task is written as crate::queue::TaskStatus::Running, with its run
id, before the graph starts, and is only rewritten once the run reaches a
terminal status. A daemon killed mid-run therefore leaves the task
Running and pointing at the run that was in flight, which is the state a
human needs to see: the run’s own report explains how far it got, and the
task can be released deliberately. The alternative — reverting the task to
Queued on the way out — would hide the abandoned run and re-spend its
quota on the next poll.
§Retries are bounded
Every attempt at a task consumes one of Opts::max_attempts, after which
the task is crate::queue::TaskStatus::Held for a human. The one
exception is a run that ended Stalled: the panel collapsed because the
agent CLIs hit their quota, which is a fact about the machine and not about
the task, so it must not spend an attempt. Without that exception a quota
outage would quietly hold the entire backlog, and the operator would come
back to a reset quota and nothing left that the loop is willing to run.
Structs§
- Current
- What the loop is working on, for the status file.
- Opts
- How the loop should behave.
- Reading
- The daemon’s published state, read permissively.
- Status
- The daemon’s liveness, published to
<home>/daemon.json. - Stop
- A cooperative stop, shared with whoever asked the loop to run.
- Verdict
- What a finished run tells the queue about the task it came from.
Constants§
- HEARTBEAT
- How often the status file is refreshed. A reader treats a status file older
than
STALE_SECSas “no daemon”, so the heartbeat has to be brisk enough that a busy daemon is never mistaken for a dead one. - POLL
- Default queue poll interval.
- SCHEMA
- On-disk format for
Status. Bumped when a field’s meaning changes. - STALE_
CLAIM - How old a claim has to be before startup sweeps it. Longer than any run this graph plausibly takes, so a sweep cannot pull a task out from under a daemon that is merely slow.
- STALE_
SECS - How old a heartbeat may be before a reader calls the daemon dead. Six missed beats: long enough to survive a slow filesystem, short enough that a crashed daemon is not still reported as running a task.
Functions§
- clear_
status - Delete the status file. Called on the way out so a clean exit reads as “no daemon” rather than as a daemon whose heartbeat merely stopped.
- current_
work - What a live daemon is working on right now, or
None. - is_
working_ on - Whether a live daemon is working on this run at this moment.
- is_
working_ on_ task - Whether a live daemon is working on this task at this moment.
- read_
status - Read
<home>/daemon.jsonpermissively, orNonewhen there is nothing usable there. - serve
- Run the loop until Ctrl-C, or until the queue drains with
Opts::once. - serve_
until serve, but stopping whenstopis set as well as on Ctrl-C.- settle
- Record a finished run against the task it came from.
- status_
path - Where the status file lives.
- sweep_
stale_ claims - Remove claim files older than
older_thanand return the task ids swept. - write_
status - Publish the status file for this process.
- write_
status_ to - Publish a status to an explicit path.