Quickstart
Extract your first structured block from a text stream. A block in the default delimiter syntax looks like this:
The opening line carries the block id and block_type; everything until !!end is the content.
Hello, block
Three steps: create a Registry, register a block class for each block_type you expect, and feed any async text stream to the processor.
import asyncio
from hother.streamblocks import Registry, StreamBlockProcessor
from hother.streamblocks.core.types import BlockEndEvent
from hother.streamblocks_examples.blocks.agent.files import FileOperations
from hother.streamblocks_examples.helpers.simulator import simple_text_stream
# Setup: registry + processor
registry = Registry()
registry.register("files_operations", FileOperations)
processor = StreamBlockProcessor(registry)
# Text with one block
text = "!!block01:files_operations\nsrc/main.py:C\n!!end"
stream = simple_text_stream(text)
# Process and extract blocks
async for event in processor.process_stream(stream):
if isinstance(event, BlockEndEvent):
block = event.get_block()
if block:
print("Extracted block:")
print(block.model_dump_json(indent=2))
The processor emits an event for everything it sees. Here we only react to BlockEndEvent, emitted when a block closes successfully, and event.get_block() returns the parsed block with typed metadata and content.
Mixing text and blocks
Real streams interleave prose and blocks. Text outside blocks is emitted as TextContentEvent, so nothing is lost:
registry = Registry()
registry.register("files_operations", FileOperations)
processor = StreamBlockProcessor(registry)
# Text to stream in chunks
text = "Some text before.\n!!block:files_operations\napp.py:C\n!!end\nSome text after."
stream = simulated_stream(text, preset="fast")
async for event in processor.process_stream(stream):
if isinstance(event, TextContentEvent):
print(f"[TEXT] {event.content.strip()}")
elif isinstance(event, BlockEndEvent):
block = event.get_block()
if block:
print("\n[BLOCK] Extracted:")
print(block.model_dump_json(indent=2))
What just happened?
Registry()defaults to the delimiter preamble syntax (!!<id>:<type>…!!end).registry.register("files_operations", FileOperations)maps the block type string to aBlockclass with typed metadata and content models.processor.process_stream(stream)consumes anyAsyncIterator[str]and yields events as lines complete.- When the closing delimiter arrives, the block's content is parsed and validated, then
BlockEndEventdelivers it.
Next steps
- Your First Custom Block: define your own metadata and content models.
- Events: the full event model, including per-section streaming deltas.
- Providers guide: plug in OpenAI, Anthropic, or Gemini streams instead of the simulator.