Read a run in code
agent.run() and await agent.arun() return a RunResult. It carries the answer and the evidence:
str | BaseModel | None
The agent’s answer. A parsed model instance when
output_type is set, None if the run did not finish.'completed' | 'max_turns' | 'failed'
How the run ended. Always check this before trusting
final_output.str | None
Why the run did not complete.
None on success.Usage
input_tokens, output_tokens, and total_tokens summed across every model call in the run.list[dict]
The conversation as the model saw it —
user, assistant, and tool messages. Pass it back into arun() to continue the conversation.list[Event]
Every step:
run_start, generation, tool_call, tool_result, message, run_end.Track token usage
See which tools ran
result.tool_calls lists the calls the model asked for, with the arguments it chose:
Tell the three endings apart
A run that did not produce an answer is not automatically an exception. Checkstatus:
- completed
- max_turns
- failed
The agent answered.
final_output is set, error is None.Failing tools do not kill the run
A tool that raises does not end the run. The error text goes back to the model, which can try something else or explain the gap. If the same tool keeps failing, it is withdrawn after two attempts so it cannot burn the remaining turns:The failure budget defaults to two attempts per tool. Adjust it per agent with
Agentor(..., max_tool_failures=3) — higher for tools that are legitimately flaky, lower to fail fast.Keep a copy of every run
A store keeps every run — and lets you finish one if the process dies:runs/<run_id>.jsonl as it happens, so you can replay a run later, and agent.resume(run_id) can pick up an interrupted one.
Watch a run as it happens
For live progress rather than a post-mortem, stream it:Next steps
Durable runs
Save runs to disk and resume them after a crash.
Streaming
Show progress to users while the agent works.
Deployment
Serve the agent as an API.
