Skip to content

Streaming

Spectra can stream workflow events in real time while a workflow is running.

Instead of waiting for the full workflow to finish, you can consume events as they happen.

This is useful for:

  • live UIs
  • chat interfaces
  • progress indicators
  • server-sent event endpoints
  • real-time token output

Stream a workflow

Use IWorkflowRunner.StreamAsync(...) to execute a workflow and consume events with await foreach.

await foreach (var evt in runner.StreamAsync(workflow, StreamMode.Tokens, initialState))
{
    switch (evt)
    {
        case TokenStreamEvent token:
            Console.Write(token.Token);
            break;

        case StepCompletedEvent step:
            Console.WriteLine($"\n[{step.NodeId}] completed in {step.Duration}");
            break;

        case WorkflowCompletedEvent done:
            Console.WriteLine($"\nWorkflow finished. Success: {done.Success}");
            break;
    }
}

There is also an overload that accepts RunContext:

await foreach (var evt in runner.StreamAsync(workflow, StreamMode.Tokens, state, runContext))
{
    // ...
}

Stream modes

StreamMode controls how much of the event stream you receive.

Mode Includes Best for
Tokens Every event, including token deltas Live LLM output
Messages Every event except TokenStreamEvent Step-level progress without token noise
Updates StepCompletedEvent, StateChangedEvent, WorkflowCompletedEvent, StepInterruptedEvent Progress views and dashboards
Values StateChangedEvent, WorkflowCompletedEvent Reactive state consumers
Custom Every event (same as Tokens) — filter downstream yourself Advanced consumers

Use the narrowest mode that matches your UI or integration.


Token streaming

When you run a workflow with StreamAsync(...), Spectra enables token-level streaming for LLM steps that support it.

Each token chunk is emitted as a TokenStreamEvent.

Field Description
Token The emitted text chunk
TokenIndex Zero-based position of the chunk within the current node's stream (resets per node)
IsComplete true on the final token for the current node's stream

Which steps support token streaming

Token streaming is supported by:

  • PromptStep
  • AgentStep
  • SessionStep

For AgentStep and SessionStep, streaming fires on iterations where no tools are in the request. When tools are present (i.e. the agent is mid-loop calling tools), the LLM response must be fully parsed before tool calls can be dispatched, so those iterations are not streamed token-by-token. In practice, a tool-using agent streams its final natural-language response once it stops calling tools.


Streaming does not replace normal events

Streaming adds a live delivery path, but it does not replace your normal event sinks.

That means:

  • your existing event sink can still write logs, audit records, or database events
  • StreamAsync(...) gives you a second live stream for the current consumer

This is important if you want both:

  • persistent observability
  • live UI updates

How it works

Internally, the runner writes workflow events into a streamable channel while still publishing them to the configured event sink.

You usually do not need to manage this directly.

The important behavior is:

  • steps emit events as they run
  • token-capable steps emit token events
  • the runner yields those events through IAsyncEnumerable<WorkflowEvent>

IEventStream

For advanced event consumption, Spectra also provides IEventStream.

public interface IEventStream
{
    IAsyncEnumerable<TEvent> SubscribeAsync<TEvent>(
        CancellationToken cancellationToken = default)
        where TEvent : WorkflowEvent;

    IAsyncEnumerable<WorkflowEvent> SubscribeAllAsync(
        StreamMode mode = StreamMode.Updates,
        CancellationToken cancellationToken = default);
}

Use this when you want:

  • typed subscriptions
  • event-specific consumers
  • filtered access without manually switching over the whole event stream

Example:

  • SubscribeAsync<StepCompletedEvent>() for step completions only
  • SubscribeAllAsync(StreamMode.Values) for state and completion events only

A simple mental model

  • RunAsync(...) waits for the workflow result
  • StreamAsync(...) gives you the workflow result as a live event stream

That is the core distinction.


What's next?

  • Events

See the full event model and built-in sinks.

Events

  • Workflow Runner

Learn how the runner drives streaming and execution.

Runner