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 |
All events, including token deltas | Live LLM output |
Messages |
All events except token deltas | Step-level progress without token noise |
Updates |
Step completion, state changes, workflow completion, interrupts | Progress views and dashboards |
Values |
State changes and workflow completion only | Reactive state consumers |
Custom |
Full stream, filter it 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 |
Position of the chunk within the current output |
Which steps support token streaming¶
Token streaming is supported by:
PromptStepAgentStepSessionStep
For AgentStep and SessionStep, only the final response is streamed.
Tool-calling iterations are not streamed token-by-token because they must be fully parsed first.
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 ct = default)
where TEvent : WorkflowEvent;
IAsyncEnumerable<WorkflowEvent> SubscribeAllAsync(
StreamMode mode = StreamMode.Updates, CancellationToken ct = 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 onlySubscribeAllAsync(StreamMode.Values)for state and completion events only
A simple mental model¶
RunAsync(...)waits for the workflow resultStreamAsync(...)gives you the workflow result as a live event stream
That is the core distinction.