Skip to main content
The AgentLoop is the unified async generator that powers both arun() (non-streaming) and arun_stream() (streaming). It yields RunOutputEvent instances throughout execution, handling tool dispatch, cancellation, human-in-the-loop pauses, and event emission.

How It Works

Both arun() and arun_stream() delegate to the same AgentLoop.run() generator:
  • arun() collects all events and builds a RunOutput at the end.
  • arun_stream() yields events directly to the caller as they happen.

Parallel Tool Calls

When the model returns multiple tool calls in a single response, the loop executes them in parallel using asyncio.gather. This is the default behavior.

Opting Out of Parallel Execution

Mark a tool as sequential=True to force it to run one-at-a-time, even when other tools in the same batch run in parallel. Use this for tools with side effects that depend on execution order.
When a batch contains both parallel and sequential tools, the loop runs all parallel tools first via asyncio.gather, then runs sequential tools one at a time.

Human-in-the-Loop (HITL)

Mark a tool with requires_confirmation=True to pause the run before executing it. The agent yields a RunPausedEvent and waits for the caller to resolve the requirement.

Rejecting a Tool Call

CancellationToken

Use a CancellationToken to cooperatively cancel a running agent from another coroutine or thread.
The loop checks token.raise_if_cancelled() at safe points — before each model call and before each tool execution. Cancellation is cooperative: the loop finishes its current atomic operation before raising AgentCancelled.

CancellationToken Reference

method
Request cancellation. Thread-safe (single bool write).
bool
Whether cancellation has been requested.
method
Raises AgentCancelled if cancellation was requested.

EventBus

The EventBus lets you register callbacks for any event type emitted during a run. The loop calls await bus.emit(event) for every event, so your handlers run inline.

Direct Registration

Available Events

All events are importable from definable.agent.events.

stop_after_tool_call

Set stop_after_tool_call=True on a tool to make the loop stop immediately after executing it, without making another model call. This is useful for tools that produce a final result that should be returned directly.

Streaming

The loop yields events that arun_stream() passes through directly: