Skip to main content

Overview

Use this guide when you want to subscribe to a CrewAI stream and print or route frames as they arrive. The basic pattern is:
Always consume the stream before reading stream.result. If you only care about text generated by LLM calls, subscribe to the llm projection and print frame.content:
frame.content is an empty string for frames that do not carry printable text, so this is also safe:
Tool events arrive on the tools channel. Use frame.type to distinguish starts, finishes, and errors.
frame.event is the structured payload for the source event. Use it for metadata such as tool names, arguments, message roles, and runtime identifiers. When a model supports streamed tool calling, CrewAI emits partial tool-call arguments as llm_stream_chunk frames on the llm channel. These frames are different from tool execution events:
  • llm channel: the model is constructing the tool call.
  • tools channel: CrewAI is executing the tool.
The current delta is stored in frame.event["chunk"]. The accumulated arguments are stored in frame.event["tool_call"]["function"]["arguments"].
Some providers emit arguments in small JSON fragments. For display, prefer the accumulated argument string over the latest delta.

Watch Flow Progress

Flow lifecycle and method execution frames arrive on the flow channel:
Use this when you want a progress log instead of token-level output.

Interleave Selected Channels

Use interleave() when you want a subset of channels while preserving their relative order:

Stream a Direct LLM Call

Direct llm.call(...) returns the final assembled result. To stream a direct LLM call, use llm.stream_events(...):

Stream a Conversational Turn

Conversational Flows expose stream_turn() for one user message:

Async Consumers

Async streams use the same channel projections:

Cleanup

Use the stream as a context manager when possible. If a client disconnects or you stop consuming early, close the stream:
For async streams, call await stream.aclose().

See Also