Give an agent a background job
Some work is longer than a conversation: matching a bank statement with invoices, filling a batch, preparing a report. A run is that job. You give the agent a goal and limits and the answer comes back at once with the run running. The agent works outside your request, for as many rounds as it needs. If it hits a case it cannot decide, it pauses and asks; you answer and it continues. When it is done it declares a summary and the things to check. You hear about every change by webhook and can cancel at any time.
Who it is for. Back offices and operations teams that delegate unattended work. Scopes. Listed above. runs:write decides which person the agent acts as, so give it only to systems you already run.
Code
The script is in examples/use-cases/background-runs.
0. Set up
Code
1. Give the agent the tools of the job
An unattended agent uses any action it is granted, including the ones that write, with nobody looking. Grant only what the job needs: two reads and one write. Actions behind an approval policy do not run inside a run either: they wait for a person.
Code
2. Write the agent
The prompt of a worker is a procedure: what to read first, when two things match, what to do when they are ambiguous (ask, never guess), what never to do and how to finish. The agent must be active, created through the API and have the api channel.
Code
3. Follow runs by webhook
Do not poll. Subscribe to the run events: run.started, run.waiting_for_answer, run.completed, run.stopped, run.failed and run.canceled. Each carries the run in data.run, exactly as GET /v2/runs/{id} would answer at that moment. They are sent at least once.
4. Give the agent a job
goal is what must be achieved, read by the agent as text from a user. actor is the person in your system the agent works for: your key vouches for them, Lelemon records that your key declared them and the run carries them to every action as the signed actor. limits can only lower the defaults (30 rounds, US$ 2, 30 minutes) up to the server maximums.
Code
The same Idempotency-Key returns the run already created, not a second one. ?dryRun=true runs the checks and queues nothing.
5. The agent asks, you answer
Two movements of the same customer with the same amount could belong to two invoices. The agent does not guess: the run pauses with status: "waiting_for_answer", question has the text and run.waiting_for_answer fires. The clear match was already recorded, signed with the actor you declared.
Code
A question is answered once: a run that is not paused answers 409 run_not_waiting. Someone from your team can also answer in the dashboard, under the agent, in Activity.
6. Read the result
The agent ends a run by calling its finish action with a summary and a list of things to check. The status is completed_unverified: nobody has verified it, so read result.summary and result.checks before you trust it.
Code
If a run ends stopped (rounds, cost, time, no_conclusion or loop) or failed, result.partial keeps the last thing the agent wrote: read it before you start the job again. See how a run ends.
7. Cancel a job
POST /v2/runs/{id}/cancel ends a run nobody is running at once. If a worker is running it, cancelRequested turns true and it ends when its next round starts. A run that already ended answers 409 run_finished.
Code
Notes
- Your backend gets real signed calls.
What you see in the dashboard
- Agent, Activity: every run with its status, rounds and actor, the question when it waits and the result when it ends. You can answer the question from there.
- Webhooks, Deliveries: each
run.*event with its delivery attempts.
What's next
- Give an agent a job that runs on its own: limits, stop reasons and what keeps a run safe.
- Approve agent actions for the actions that must wait for a person.
- Track usage and cap conversations.