The Event Stream
In the previous examples, we used.collect() to get the final result. When you call a Runnable, it doesn’t just return the answer - it returns a stream of events that tell you what’s happening step by step (an async generator). The .collect() method waits for all events and gives you just the final answer.
You can iterate through the async generator to process events in real-time:
- Monitor execution progress in real-time
- Handle streaming responses from LLMs
- Debug execution flow
- Build reactive user interfaces
Event Logging
In reality, you don’t need to manually print events. By default, events are logged to standard output by the framework. You can control logging behavior with these environment variables:TIMBAL_LOG_EVENTS: Which events to log (default:"START,OUTPUT")TIMBAL_LOG_FORMAT: Log format -"dev"for human-readable or"json"for structured (default)TIMBAL_LOG_LEVEL: Standard log level (default:"INFO")
Event Types
Events are the communication mechanism that Runnables use to stream information throughout their execution lifecycle. Every Runnable execution produces a sequence of events that can be consumed in real-time or collected for later processing. Events are designed to be lightweight. For comprehensive execution data, see Traces. Every execution produces at least a Start event (when it begins) and an Output event (when it finishes). LLMs and streaming operations also produce Chunk or Delta events for intermediate results. The following examples show what these events look like for an LLM interaction:Start Event
Signals the beginning of an execution.These fields are present in all events to identify their source - the framework handles this automatically. We’ll explore this in greater detail in advanced sections.
Chunk Event
Contains streaming or intermediate results during execution. Thechunk property contains each piece of the response as it’s generated during streaming.
Deprecation Notice: ChunkEvents are simple and untyped, and will be deprecated in a future release in favor of Delta Events. Delta Events provide structured, typed streaming with semantic information about different content types (text, tool calls, thinking) and better observability. We recommend migrating to Delta Events for new projects.
Delta Events
For advanced use cases requiring fine-grained control over streaming content, Timbal provides Delta Events. Unlike simple ChunkEvents, DeltaEvents provide typed, structured information about different types of streaming content.Delta events are opt-in via the environment variable:
Delta Event Structure
Delta Item Types
DeltaEvents contain one of several typed items: TextItem - Streaming text output:ToolInputItem events will be emitted for a single tool call. You need to accumulate these deltas and parse the complete JSON afterwards.
ToolResultItem - Tool execution result:
CustomItem for streaming content that doesn’t fit standard types (e.g., multimodal content, provider-specific features, experimental data). This allows custom collectors and tools to emit arbitrary typed data while participating in the delta event system.
Using Delta Events
Benefits of Delta Events
- Type Safety: Each delta item has specific fields and types
- Semantic Information: Know exactly what type of content is streaming
- Better Observability: Track tool calls, thinking, and text separately
- UI Flexibility: Render different content types with appropriate components
- Structured Logging: Monitor different content types independently
Backward Compatibility
Delta Events are opt-in.When
TIMBAL_DELTA_EVENTS is disabled (default):- Text content is emitted as
ChunkEventfor backward compatibility - Other delta types (tool calls, thinking) are filtered out
- Existing code continues to work unchanged
- All content is emitted as structured
DeltaEventinstances - No
ChunkEventinstances for LLM text output - Full observability into all streaming content types
Output Event
Contains the final result and signals completion. Contains either the finaloutput result (if successful) or error information (if something went wrong).
Handling Errors
When a Runnable encounters an error during execution, it won’t raise an exception. Instead, it will always return anOutputEvent with error information. This ensures the event stream continues and you can handle errors gracefully: