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
Botharun() and arun_stream() delegate to the same AgentLoop.run() generator:
arun()collects all events and builds aRunOutputat 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 usingasyncio.gather. This is the default behavior.
Opting Out of Parallel Execution
Mark a tool assequential=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.
asyncio.gather, then runs sequential tools one at a time.
Human-in-the-Loop (HITL)
Mark a tool withrequires_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 aCancellationToken to cooperatively cancel a running agent from another coroutine or thread.
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
Request cancellation. Thread-safe (single bool write).
Whether cancellation has been requested.
Raises
AgentCancelled if cancellation was requested.EventBus
TheEventBus 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
| Event | Emitted when |
|---|---|
RunStartedEvent | The agentic loop begins |
RunContentEvent | A content chunk is produced (streaming) |
RunContentCompletedEvent | All content chunks for one model call are done |
RunCompletedEvent | The loop finishes with a final response |
RunPausedEvent | A HITL tool pauses the run |
RunContinuedEvent | A paused run is resumed |
RunErrorEvent | An error occurs during the run |
RunCancelledEvent | The run is cancelled via CancellationToken |
ToolCallStartedEvent | A tool call begins |
ToolCallCompletedEvent | A tool call finishes |
ToolCallErrorEvent | A tool call raises an exception |
ReasoningStartedEvent | The thinking phase begins |
ReasoningStepEvent | A reasoning step is produced |
ReasoningCompletedEvent | The thinking phase finishes |
KnowledgeRetrievalStartedEvent | Knowledge retrieval begins |
KnowledgeRetrievalCompletedEvent | Knowledge retrieval finishes |
MemoryRecallStartedEvent | Memory recall begins |
MemoryRecallCompletedEvent | Memory recall finishes |
MemoryUpdateStartedEvent | Memory update begins |
MemoryUpdateCompletedEvent | Memory update finishes |
ModelCallStartedEvent | A model call is about to execute (includes messages snapshot, tools, model_id) |
ModelCallCompletedEvent | A model call returned (includes content, tool_calls, metrics) |
PhaseStartedEvent | A pipeline phase begins execution |
PhaseCompletedEvent | A pipeline phase finishes execution |
SubAgentSpawnedEvent | A sub-agent is spawned by the parent agent |
SubAgentCompletedEvent | A sub-agent completes successfully |
SubAgentFailedEvent | A sub-agent fails with an error |
definable.agent.events.
stop_after_tool_call
Setstop_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 thatarun_stream() passes through directly: