You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 19, 2026. It is now read-only.
Copy file name to clipboardExpand all lines: docs/patterns/running-tasks.mdx
+43Lines changed: 43 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -369,3 +369,46 @@ The orchestrator is instantiated with the following arguments:
369
369
370
370
You can then use the orchestrator's `run()` method to step through the loop manually. If you call `run()` with no arguments, it will continue until all of the provided tasks are complete. You can provide `max_llm_calls` and `max_agent_turns` to further limit the behavior.
371
371
372
+
373
+
## Using handlers
374
+
375
+
Handlers in ControlFlow provide a way to observe and react to events that occur during task execution. They allow you to customize logging, monitoring, or take specific actions based on the orchestration process.
376
+
377
+
Handlers implement the `Handler` interface, which defines methods for various events that can occur during task execution, including agent messages (and message deltas), user messages, tool calls, tool results, orchestrator sessions starting or stopping, and more.
378
+
379
+
ControlFlow includes a built-in `PrintHandler` that pretty-prints agent responses and tool calls to the terminal. It's used by default if `controlflow.settings.pretty_print_agent_events=True` and no other handlers are provided.
380
+
381
+
### How handlers work
382
+
383
+
Whenever an event is generated by ControlFlow, the orchestrator will pass it to all of its registered handlers. Each handler will dispatch to one of its methods based on the type of event. For example, an `AgentMessage` event will be handled by the handler's `on_agent_message` method. The `on_event` method is always called for every event. This table describes all event types and the methods they are dispatched to:
384
+
385
+
| Event Type | Method |
386
+
|------------|--------|
387
+
|`Event` (all events) |`on_event`|
388
+
|`UserMessage`|`on_user_message`|
389
+
|`OrchestratorMessage`|`on_orchestrator_message`|
390
+
|`AgentMessage`|`on_agent_message`|
391
+
|`AgentMessageDelta`|`on_agent_message_delta`|
392
+
|`ToolCall`|`on_tool_call`|
393
+
|`ToolResult`|`on_tool_result`|
394
+
|`OrchestratorStart`|`on_orchestrator_start`|
395
+
|`OrchestratorEnd`|`on_orchestrator_end`|
396
+
|`OrchestratorError`|`on_orchestrator_error`|
397
+
|`EndTurn`|`on_end_turn`|
398
+
399
+
400
+
### Writing a custom handler
401
+
402
+
To create a custom handler, subclass the `Handler` class and implement the methods for the events you're interested in. Here's a simple example that logs agent messages:
403
+
404
+
```python
405
+
import controlflow as cf
406
+
from controlflow.orchestration.handler import Handler
407
+
from controlflow.events.events import AgentMessage
0 commit comments