Skip to main content
Read streaming data from your tasks in backend code. Consume AI completions as they generate, process file chunks, or handle any continuous data your tasks produce.
To emit streams from your tasks, see Streaming data from tasks. For React components, see Streaming in React.
Run-scoped streams are the right primitive for ephemeral I/O that lives inside a single run’s lifetime. For durable, long-lived channels that outlive a run, see chat.agent: it’s built on a Session row that owns the chat’s runs and exposes bidirectional .in / .out channels addressed by a durable id.

Reading streams

The recommended approach is to use defined streams for full type safety:

Direct stream reading

If you prefer not to use defined streams, you can read directly by specifying the stream key:

Reading from the default stream

Every run has a default stream, so you can omit the stream key:

Stream options

The read() method accepts several options for controlling stream behavior:

Timeout

Set a timeout to stop reading if no data is received within a specified time:

Start index

Resume reading from a specific chunk index (useful for reconnection scenarios):

Abort signal

Use an AbortSignal to cancel stream reading:

Combining options

You can combine multiple options:

Practical examples

Reading AI streaming responses

Here’s a complete example of consuming an AI stream from your backend:

Reading multiple streams

If a task emits multiple streams, you can read them concurrently or sequentially:

Piping streams to HTTP responses

You can pipe streams directly to HTTP responses for server-sent events (SSE):

Implementing retry logic

Handle transient errors with retry logic:

Processing streams in chunks

Process streams in batches for efficiency:

Using with runs.subscribeToRun()

For more advanced use cases where you need both the run status and streams, you can use the runs.subscribeToRun() method with .withStreams():
For most use cases, we recommend using streams.read() with defined streams for better type safety and clearer code. Use runs.subscribeToRun().withStreams() only when you need to track both run status and stream data simultaneously.