Streaming and Real-time Events
Relevant source files
The following files were used as context for generating this wiki page: - [loom-proto/proto/streaming.proto](https://github.com/Alonso-pixel/loom/blob/HEAD/loom-proto/proto/streaming.proto) - [loom-py/src/loom/streaming/__init__.py](https://github.com/Alonso-pixel/loom/blob/HEAD/loom-py/src/loom/streaming/__init__.py) - [loom-py/src/loom/cli/ui.py](https://github.com/Alonso-pixel/loom/blob/HEAD/loom-py/src/loom/cli/ui.py) - [loom-py/tests/unit/test_streaming_types.py](https://github.com/Alonso-pixel/loom/blob/HEAD/loom-py/tests/unit/test_streaming_types.py) - [core/src/dashboard/frontend/src/pages/Index.tsx](https://github.com/Alonso-pixel/loom/blob/HEAD/core/src/dashboard/frontend/src/pages/Index.tsx) - [loom-py/README.md](https://github.com/Alonso-pixel/loom/blob/HEAD/loom-py/README.md) - [core/src/dashboard/README.md](https://github.com/Alonso-pixel/loom/blob/HEAD/core/src/dashboard/README.md)The Loom streaming protocol is a core feature designed for real-time communication between clients (like the CLI or Dashboard) and backend cognitive agents. Its primary purpose is to stream partial outputs, such as LLM responses or agent "thinking" steps, as they are generated. This provides a responsive and transparent user experience, allowing users to see results immediately rather than waiting for the full response to be computed.
The system is built on an event-driven architecture, where clients and agents communicate over an event bus. The streaming protocol defines a set of Protobuf messages for managing the stream lifecycle, from initiation to chunk delivery and final completion. The Python SDK provides high-level abstractions for both producing and consuming these streams.
Sources: loom-proto/proto/streaming.proto:5-8, loom-py/README.md:80-81, loom-py/src/loom/streaming/init.py:3-6
Architecture and Message Flow
The streaming architecture involves a client, a bridge, and a backend agent. The client sends a request, and the agent replies with a series of chunks, culminating in a completion message.
Sources: loom-proto/proto/streaming.proto:9-15
This diagram shows the sequence of messages exchanged during a typical streaming session.
Dashboard Event Streaming
The Loom Dashboard provides real-time observability by consuming a stream of system events via Server-Sent Events (SSE). The frontend establishes a connection to an /api/events/stream endpoint, receives events, and updates the UI to show a live event log, agent communications, and network graphs. This mechanism is distinct from the agent-to-agent streaming protocol but serves the similar purpose of providing real-time updates.
Sources: core/src/dashboard/README.md:10-12, core/src/dashboard/frontend/src/pages/Index.tsx:200-234
Protocol Definition
The streaming protocol is formally defined using Protocol Buffers in streaming.proto. This ensures cross-language compatibility and a well-defined message structure.
Sources: loom-proto/proto/streaming.proto
Key Messages
StreamRequest
A message sent by a client to initiate a streaming response.
| Field | Type | Description |
|---|---|---|
id | string | Unique ID for the request. |
message | string | The prompt or message to be processed. |
thread_id | string | ID for maintaining conversation continuity. |
sender | string | ID of the requesting client or agent. |
reply_to | string | The topic where stream chunks should be sent. |
context | repeated string | Optional context from previous messages. |
options | StreamOptions | Options to configure the streaming behavior. |
Sources: loom-proto/proto/streaming.proto:130-149
StreamChunk
A single piece of content in a stream. An agent can send many of these for a single request.
| Field | Type | Description |
|---|---|---|
correlation_id | string | ID to match the chunk with the original StreamRequest. |
content | string | The content chunk, typically text. |
sequence | uint32 | A 0-indexed number for ordering chunks correctly. |
content_type | StreamContentType | A hint about the type of content in the chunk. |
metadata | map<string, string> | Optional key-value metadata for the chunk. |
timestamp_ms | int64 | The timestamp when the chunk was generated. |
Sources: loom-proto/proto/streaming.proto:18-34
StreamComplete
A final message that signals the end of a stream.
| Field | Type | Description |
|---|---|---|
correlation_id | string | ID to match with the original StreamRequest. |
final_content | string | Optional final aggregated response for convenience. |
total_chunks | uint32 | The total number of StreamChunk messages sent. |
status | StreamStatus | The completion status (e.g., OK, ERROR, TIMEOUT). |
error | StreamError | Contains error details if the status is not OK. |
stats | StreamStats | Execution statistics for the completed stream. |
Sources: loom-proto/proto/streaming.proto:61-79
Enumerations
StreamContentType
This enum categorizes the content of a StreamChunk, which is used by clients like the loom chat UI to render the output appropriately.
| Value | Description |
|---|---|
STREAM_CONTENT_TEXT | Default text content, like an LLM response. |
STREAM_CONTENT_THINKING | Internal reasoning or "Chain of Thought" content. |
STREAM_CONTENT_TOOL_CALL | A tool is being called. |
STREAM_CONTENT_TOOL_RESULT | The result from a tool call. |
STREAM_CONTENT_ERROR | An error message. |
STREAM_CONTENT_STATUS | A status or progress update. |
STREAM_CONTENT_MARKDOWN | Markdown-formatted content. |
STREAM_CONTENT_CODE | A block of code. |
Sources: loom-proto/proto/streaming.proto:37-58, loom-py/tests/unit/test_streaming_types.py:16-25
StreamStatus
Indicates the final status of a completed stream.
| Value | Description |
|---|---|
STREAM_STATUS_OK | The stream completed successfully. |
STREAM_STATUS_CANCELLED | The stream was cancelled by the client. |
STREAM_STATUS_TIMEOUT | The operation timed out. |
STREAM_STATUS_ERROR | An error occurred during processing. |
STREAM_STATUS_TRUNCATED | Completed but the output was truncated (e.g., hit a token limit). |
Sources: loom-proto/proto/streaming.proto:82-96, loom-py/tests/unit/test_streaming_types.py:32-37
Python SDK Implementation
The loom-py SDK provides Pythonic wrappers around the Protobuf definitions, making it easy to work with streaming.
Sources: loom-py/src/loom/streaming/init.py
Python Data Classes
The loom.streaming.types module defines dataclasses that mirror the Protobuf messages, such as StreamChunk, StreamComplete, StreamRequest, etc. These classes are used throughout the Python SDK.
Sources: loom-py/src/loom/streaming/init.py:40-52, loom-py/tests/unit/test_streaming_types.py
This diagram shows the relationship between the main Python classes in the streaming module.
Client-Side Usage (StreamingClient)
A client application can use StreamingClient to send a request and asynchronously iterate over the response chunks.
Example:
from loom.streaming import StreamingClient
client = StreamingClient(bridge_addr="127.0.0.1:50051")
await client.connect()
# Send message and receive streaming response
async for chunk in client.stream_message("Explain quantum computing"):
print(chunk.content, end="", flush=True)
Sources: loom-py/src/loom/streaming/init.py:20-27
Handler-Side Usage (StreamingHandler)
A backend agent uses StreamingHandler to produce a stream of chunks in response to an event.
Example:
from loom.streaming import StreamingHandler
# In an agent's event handler
async def on_event(ctx, topic, event):
if event.type == "user.message":
handler = StreamingHandler(ctx)
# Assuming `cognitive.run_stream` yields LLM chunks
async for llm_chunk in cognitive.run_stream(event.payload):
await handler.send_chunk(event, llm_chunk)
await handler.send_complete(event)
Sources: loom-py/src/loom/streaming/init.py:29-36
CLI Chat and UI Rendering
The interactive chat CLI (loom chat) is a primary consumer of the streaming protocol. It uses a ReactStreamParser to incrementally parse the incoming stream of StreamChunk messages and render them in a structured way.
Sources: loom-py/src/loom/cli/ui.py:448-472, loom-py/src/loom/cli/README.md:92-95
The parser identifies different sections of a ReAct-style response, such as "Thought", "Action", and "FINAL ANSWER", and emits corresponding events. The UI then uses these events to render a rich, real-time display of the agent's reasoning process.
This flowchart illustrates the logic of the ReactStreamParser.
Sources: loom-py/src/loom/cli/ui.py:474-585
The ReactStreamRenderer or SimpleStreamRenderer then takes these parsed events and displays them in the terminal, providing visualizations for thinking steps, tool calls, and results.
Sources: loom-py/src/loom/cli/ui.py:698-709, loom-py/src/loom/cli/ui.py:814-827
Summary
The streaming and real-time event system is fundamental to Loom's interactive and observable nature. By defining a clear protocol with streaming.proto and providing easy-to-use SDK components like StreamingClient and StreamingHandler, Loom enables developers to build agents that deliver immediate feedback. This capability is showcased in the loom chat CLI, which uses sophisticated parsing and rendering to give users a clear window into an agent's cognitive processes as they happen.